////////////////////////// // use texture.js without d3 to create discerning patterns on the email blocks ///////////////////////////////////// // some faked dom, see https://github.com/riccardoscalco/textures/issues/17 function dom(name) { this.name = name; this.els = []; this.attrs = {}; } dom.prototype.append = function(name) { if (name === "defs") return this; if (this.name === undefined) { this.name = name; return this; } var el = new dom(name); this.els.push(el); return el; } dom.prototype.attr = function(key, value) { this.attrs[key] = value; return this; } dom.prototype.toString = function() { var attrs = []; var k; for (k in this.attrs) { attrs += " " + k + "='" + this.attrs[k] + "'"; } if (this.els.length) { return "<"+this.name+attrs+">"+this.els.map(function(el) { return el.toString()}).join('\n')+""; } else { return "<"+this.name+attrs+"/>" } } //////////// end of faked dom /////////////////////////////// let categoryMap = {}; let textureMap = {}; function getColoredTexture(i, color) { let j = i % 11; // update when adding items to switch: switch(j) { case 0: return textures.lines().size(4).strokeWidth(1).stroke(color); case 1: return textures.circles().radius(2).size(5).fill('none').strokeWidth(1).stroke(color).complement(); case 2: return textures.lines().size(10).orientation("3/8").stroke(color); case 3: return textures.lines().heavier(4).thinner(.8).stroke(color); case 4: return textures.paths().d("hexagons").size(3).strokeWidth(1).stroke(color); case 5: return textures.lines().orientation("vertical", "horizontal").size(4).strokeWidth(1).shapeRendering("crispEdges").stroke(color); case 6: return textures.paths().d("hexagons").size(5).strokeWidth(2).stroke("rgba(0,0,0,0)").fill(color); case 7: return textures.circles().size(4).stroke(color); case 8: return textures.circles().thicker().complement().stroke(color); case 9: return textures.paths().d("caps").lighter().thicker().size(5).stroke(color); case 10: return textures.paths().d("hexagons").size(4).strokeWidth(2).stroke(color); // textures.lines().size(4).strokeWidth(1).orientation("-3/8"), } }; const categoryColors = { "person": "#f00", "vehicle": "#0f0", "outdoor": "#006", "animal": "#ff0", "food": "#0ff", "furniture": "#f0f", "indoor": "#fff", "electronic": "#390", "kitchen": "#930", "accessory": "#f90", "sports": "#f09", } function getColorForSuperCategory(name) { return categoryColors[name]; } function getTextureForCategory(id) { let hash = id; if(!textureMap.hasOwnProperty(hash)) { let color = categoryColors[categoryMap[id]['supercategory']]; textureMap[hash] = getColoredTexture(id, color); } return textureMap[hash]; } class CocoCanvas { start(){ this.catNavEl = document.getElementById('catNav'); this.canvas = document.getElementById('svgCanvas'); this.loadNav() } loadNav() { let r = new Request('/categories.json'); fetch(r) .then(response => response.json()) .then(categories => { for(let cat of categories) { categoryMap[cat['id']] = cat; } this.buildNav(categories); }).catch(function(e){ console.error(e); }); } buildNav(categories) { let ulEl = crel('ul'); for(let cat of categories) { ulEl.appendChild( crel('li', { 'id': 'category-' + cat['id'], 'on': { 'click': (e) => { this.requestAnnotation(cat['id']); } } }, cat['name']) ); } this.catNavEl.appendChild(ulEl); let defsEl = document.createElementNS("http://www.w3.org/2000/svg", 'defs'); for(let cat of categories) { let texture = getTextureForCategory(cat['id']); let sel = new dom(); texture(sel); defsEl.innerHTML += sel.toString(); } this.canvas.appendChild(defsEl); } requestAnnotation(category_id) { let r = new Request(`/annotation.json?category=${category_id}&normalise=100`); fetch(r) .then(response => response.json()) .then(annotation => { this.addAnnotationAsShape(annotation); }).catch(function(e){ console.error(e); });; } pointsToD(points) { let start = points.shift() let d = `M${start[0].toPrecision(4)} ${start[1].toPrecision(4)} L `; points = points.map((p) => `${p[0].toPrecision(4)} ${p[1].toPrecision(4)}`); d += points.join(' '); return d; } getMousePosition(evt) { // from http://www.petercollingridge.co.uk/tutorials/svg/interactive/dragging/ let CTM = this.canvas.getScreenCTM(); return { x: (evt.clientX - CTM.e) / CTM.a, y: (evt.clientY - CTM.f) / CTM.d }; } addAnnotationAsShape(annotation) { console.log('Add annotation', annotation); let category = categoryMap[annotation['category_id']] let texture = getTextureForCategory(category['id']); let x = 500 - annotation['bbox'][2]/2; let y = 500 - annotation['bbox'][3]/2; let annEl = crel(document.createElementNS("http://www.w3.org/2000/svg", 'g'), { 'data-id': annotation['id'], 'transform': `translate(${x}, ${y})`, 'on': { 'mousedown': function(downE) { console.log(downE); console.log(this) let offset = this.getMousePosition(downE); // offset.x -= parseFloat(downE.target.getAttributeNS(null, "x")); // offset.y -= parseFloat(downE.target.getAttributeNS(null, "y")); // Get initial translation amount console.log(annEl.transform.baseVal); let transform = annEl.transform.baseVal.getItem(0); offset.x -= transform.matrix.e; offset.y -= transform.matrix.f; let moveEvent = (moveE) => { let coord = this.getMousePosition(moveE); transform.matrix.e = coord.x - offset.x; transform.matrix.f = coord.y - offset.y; // annEl.setAttributeNS(null, "x", coord.x - offset.x); // annEl.setAttributeNS(null, "y", coord.y - offset.y); }; document.addEventListener('mousemove', moveEvent); document.addEventListener('mouseup', (upE) => { document.removeEventListener('mousemove', moveEvent); }); }.bind(this) } }); for(let segment of annotation['segments']) { let pathEl = crel(document.createElementNS("http://www.w3.org/2000/svg", 'path'), { 'fill': texture.url(), 'd': this.pointsToD(segment) }); annEl.appendChild(pathEl); } console.log(annEl); this.canvas.appendChild(annEl); } } let cc = new CocoCanvas(); cc.start();