
commit
1702cce9d1
12 changed files with 825 additions and 0 deletions
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
|
||||
Build array of images sorted by size: |
||||
|
||||
```bash |
||||
python zoom_animation.py --annotations ../../datasets/COCO/annotations/instances_train2017.json --output zoom --category_id 18 |
||||
``` |
||||
|
||||
Turn into png |
||||
|
||||
```bash |
||||
cd zoom/dog |
||||
for file in *.svg; do inkscape -z -f "${file}" -w 640 -e "../dog_png/${file}.png"; done |
||||
``` |
||||
|
||||
Turn png into mp4 |
||||
|
||||
```bash |
||||
cd ../dog_png |
||||
#ffmpeg -r 1 -i %d_*.png -pix_fmt yuv420p bloch2.mp4 |
||||
ffmpeg -f image2 -pattern_type glob -i '*.png' ../dog.mp4 |
||||
|
||||
``` |
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
BEGIN TRANSACTION; |
||||
CREATE TABLE IF NOT EXISTS "segments" ( |
||||
"id" INTEGER UNIQUE, |
||||
"annotation_id" INTEGER, |
||||
"points" TEXT, |
||||
PRIMARY KEY("id") |
||||
) WITHOUT ROWID; |
||||
CREATE TABLE IF NOT EXISTS "categories" ( |
||||
"id" INTEGER UNIQUE, |
||||
"supercategory" TEXT, |
||||
"name" TEXT UNIQUE, |
||||
PRIMARY KEY("id") |
||||
) WITHOUT ROWID; |
||||
CREATE TABLE IF NOT EXISTS "images" ( |
||||
"id" INTEGER UNIQUE, |
||||
"flickr_url" TEXT, |
||||
"coco_url" TEXT, |
||||
"width" FLOAT, |
||||
"height" FLOAT, |
||||
"date_captured" DATETIME, |
||||
PRIMARY KEY("id","id") |
||||
) WITHOUT ROWID; |
||||
CREATE TABLE IF NOT EXISTS "annotations" ( |
||||
"id" INTEGER UNIQUE, |
||||
"image_id" INTEGER, |
||||
"category_id" INTEGER, |
||||
"iscrowd" BOOL, |
||||
"area" FLOAT, |
||||
"bbox_top" FLOAT, |
||||
"bbox_left" FLOAT, |
||||
"bbox_width" FLOAT, |
||||
"bbox_height" FLOAT, |
||||
PRIMARY KEY("id") |
||||
) WITHOUT ROWID; |
||||
CREATE INDEX IF NOT EXISTS "segments_annotation" ON "segments" ( |
||||
"annotation_id" |
||||
); |
||||
CREATE INDEX IF NOT EXISTS "annotations_image" ON "annotations" ( |
||||
"image_id" |
||||
); |
||||
CREATE INDEX IF NOT EXISTS "annotations_category" ON "annotations" ( |
||||
"category_id" |
||||
); |
||||
COMMIT; |
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
import pycocotools.coco |
||||
import argparse |
||||
import logging |
||||
import tqdm |
||||
import urllib.request |
||||
import os |
||||
|
||||
logger = logging.getLogger("coco") |
||||
|
||||
argParser = argparse.ArgumentParser(description='Find all images with single segments and generate svg') |
||||
argParser.add_argument( |
||||
'--annotations', |
||||
type=str, |
||||
default='../../datasets/COCO/annotations/instances_train2017.json' |
||||
) |
||||
argParser.add_argument( |
||||
'--output', |
||||
type=str, |
||||
help='Output directory' |
||||
) |
||||
args = argParser.parse_args() |
||||
|
||||
|
||||
logger.info(f"Load {args.annotations}") |
||||
coco = pycocotools.coco.COCO(args.annotations) |
||||
|
||||
|
||||
for img_id, annotations in tqdm.tqdm(coco.imgToAnns.items()): |
||||
if len(annotations) != 1: |
||||
continue |
||||
|
||||
annotation = annotations[0] # we have only one |
||||
category = coco.cats[annotation['category_id']]['name'] |
||||
fn = os.path.join(args.output, f"{category}_{img_id}.jpg") |
||||
if not os.path.exists(fn): |
||||
urllib.request.urlretrieve(coco.imgs[img_id]['coco_url'], fn) |
@ -0,0 +1,125 @@
@@ -0,0 +1,125 @@
|
||||
import tornado.ioloop |
||||
import tornado.web |
||||
import tornado.websocket |
||||
import argparse |
||||
import logging |
||||
import coloredlogs |
||||
from coco.storage import COCOStorage |
||||
import json |
||||
from urllib.parse import urlparse |
||||
|
||||
logger = logging.getLogger('coco.server') |
||||
|
||||
class JsonEncoder(json.JSONEncoder): |
||||
def default(self, obj): |
||||
method = getattr(obj, "forJson", None) |
||||
if callable(method ): |
||||
return obj.forJson() |
||||
# Let the base class default method raise the TypeError |
||||
return json.JSONEncoder.default(self, obj) |
||||
|
||||
class RestHandler(tornado.web.RequestHandler): |
||||
def initialize(self, storage: COCOStorage): |
||||
self.storage = storage |
||||
self.set_header("Content-Type", "application/json") |
||||
|
||||
def get(self, *params): |
||||
self.write(json.dumps(self.getData(*params), cls=JsonEncoder)) |
||||
|
||||
class CategoryHandler(RestHandler): |
||||
def getData(self): |
||||
return self.storage.getCategories() |
||||
|
||||
class AnnotationHandler(RestHandler): |
||||
def getData(self): |
||||
# get specific annotation |
||||
annotation_id = self.get_argument('id', None) |
||||
annotation_id = None if not annotation_id else int(annotation_id) |
||||
|
||||
# get by category id |
||||
category_id = self.get_argument('category', None) |
||||
category_id = None if not category_id else int(category_id) |
||||
|
||||
normalise = self.get_argument('normalise', False) |
||||
normalise = int(normalise) if normalise is not False else False |
||||
|
||||
# category_id = None if not category_id else int(category_id) |
||||
|
||||
logger.debug(f'Get annotation id: {annotation_id}, category: {category_id}, normalised: {normalise}') |
||||
|
||||
annotation = self.storage.getRandomAnnotation(annotation_id=annotation_id, category_id=category_id) |
||||
if normalise: |
||||
return annotation.getNormalised(normalise, normalise) |
||||
return annotation |
||||
|
||||
|
||||
class WebSocketHandler(tornado.websocket.WebSocketHandler): |
||||
CORS_ORIGINS = ['localhost', 'coco.local', 'r3.local'] |
||||
|
||||
def check_origin(self, origin): |
||||
parsed_origin = urlparse(origin) |
||||
# parsed_origin.netloc.lower() gives localhost:3333 |
||||
valid = parsed_origin.hostname in self.CORS_ORIGINS |
||||
return valid |
||||
|
||||
# the client connected |
||||
def open(self, p = None): |
||||
WebSocketHandler.connections.add(self) |
||||
logger.info("New client connected") |
||||
self.write_message("hello!") |
||||
|
||||
# the client sent the message |
||||
def on_message(self, message): |
||||
logger.debug(f"recieve: {message}") |
||||
|
||||
|
||||
class StaticFileWithHeaderHandler(tornado.web.StaticFileHandler): |
||||
def set_extra_headers(self, path): |
||||
"""For subclass to add extra headers to the response""" |
||||
if path[-5:] == '.html': |
||||
self.set_header("Access-Control-Allow-Origin", "*") |
||||
|
||||
def make_app(db_filename, debug): |
||||
storage = COCOStorage(db_filename) |
||||
|
||||
return tornado.web.Application([ |
||||
(r"/ws(.*)", WebSocketHandler), |
||||
(r"/categories.json", CategoryHandler, {'storage': storage}), |
||||
(r"/annotation.json", AnnotationHandler, {'storage': storage}), |
||||
(r"/(.*)", StaticFileWithHeaderHandler, |
||||
{"path": 'www', "default_filename": 'index.html'}), |
||||
], debug=debug) |
||||
|
||||
if __name__ == "__main__": |
||||
argParser = argparse.ArgumentParser(description='Server for COCO web interface') |
||||
argParser.add_argument( |
||||
'--port', |
||||
'-P', |
||||
type=int, |
||||
default=8888, |
||||
help='Port to listen on' |
||||
) |
||||
argParser.add_argument( |
||||
'--db', |
||||
type=str, |
||||
metavar='DATABASE', |
||||
required=True, |
||||
help='Database to serve from' |
||||
) |
||||
argParser.add_argument( |
||||
'--verbose', |
||||
'-v', |
||||
action='store_true', |
||||
help='Increase log level' |
||||
) |
||||
args = argParser.parse_args() |
||||
|
||||
loglevel = logging.DEBUG if args.verbose else logging.INFO |
||||
coloredlogs.install( |
||||
level=loglevel, |
||||
fmt="%(asctime)s %(hostname)s %(name)s[%(process)d] %(levelname)s %(message)s" |
||||
) |
||||
|
||||
app = make_app(args.db, debug=args.verbose ) |
||||
app.listen(args.port) |
||||
tornado.ioloop.IOLoop.current().start() |
@ -0,0 +1,106 @@
@@ -0,0 +1,106 @@
|
||||
import pycocotools.coco |
||||
import argparse |
||||
import logging |
||||
import os |
||||
import pprint |
||||
import sqlite3 |
||||
|
||||
logging.basicConfig(level=logging.INFO) |
||||
logger = logging.getLogger("coco") |
||||
|
||||
argParser = argparse.ArgumentParser(description='Create shape SVG\'s') |
||||
argParser.add_argument( |
||||
'--annotations', |
||||
type=str, |
||||
default='../../datasets/COCO/annotations/instances_val2017.json' |
||||
) |
||||
argParser.add_argument( |
||||
'--categories', |
||||
action='store_true', |
||||
help='Show categories' |
||||
) |
||||
argParser.add_argument( |
||||
'--propagate', |
||||
type=str, |
||||
metavar='DATABASE', |
||||
help='Store data in sqlite db' |
||||
) |
||||
args = argParser.parse_args() |
||||
|
||||
|
||||
logger.info(f"Load {args.annotations}") |
||||
coco = pycocotools.coco.COCO(args.annotations) |
||||
|
||||
|
||||
if args.categories: |
||||
cats = {} |
||||
for id, cat in coco.cats.items(): |
||||
if cat['supercategory'] not in cats: |
||||
cats[cat['supercategory']] = [] |
||||
cats[cat['supercategory']].append(cat) |
||||
# pp = pprint.PrettyPrinter(indent=4) |
||||
pprint.pprint(cats, sort_dicts=False) |
||||
|
||||
if args.propagate: |
||||
if not os.path.exists(args.propagate): |
||||
con = sqlite3.connect(args.propagate) |
||||
cur = con.cursor() |
||||
with open('coco.sql', 'r') as fp: |
||||
cur.executescript(fp.read()) |
||||
con.close() |
||||
|
||||
con = sqlite3.connect(args.propagate) |
||||
logger.info("Create categories") |
||||
cur = con.cursor() |
||||
cur.executemany('INSERT OR IGNORE INTO categories(id, supercategory, name) VALUES (:id, :supercategory, :name)', coco.cats.values()) |
||||
con.commit() |
||||
|
||||
logger.info("Images...") |
||||
cur.executemany(''' |
||||
INSERT OR IGNORE INTO images(id, flickr_url, coco_url, width, height, date_captured) |
||||
VALUES (:id, :flickr_url, :coco_url, :width, :height, :date_captured) |
||||
''', coco.imgs.values()) |
||||
con.commit() |
||||
|
||||
logger.info("Annotations...") |
||||
|
||||
|
||||
def annotation_generator(): |
||||
for c in coco.anns.values(): |
||||
ann = c.copy() |
||||
ann['bbox_top'] = ann['bbox'][1] |
||||
ann['bbox_left'] = ann['bbox'][0] |
||||
ann['bbox_width'] = ann['bbox'][2] |
||||
ann['bbox_height'] = ann['bbox'][3] |
||||
yield ann |
||||
|
||||
cur.executemany(''' |
||||
INSERT OR IGNORE INTO annotations(id, image_id, category_id, iscrowd, area, bbox_top, bbox_left, bbox_width, bbox_height) |
||||
VALUES (:id, :image_id, :category_id, :iscrowd, :area, :bbox_top, :bbox_left, :bbox_width, :bbox_height) |
||||
''', annotation_generator()) |
||||
con.commit() |
||||
|
||||
|
||||
logger.info("Segments...") |
||||
|
||||
def segment_generator(): |
||||
for ann in coco.anns.values(): |
||||
for i, seg in enumerate(ann['segmentation']): |
||||
yield { |
||||
'id': ann['id']*10 + i, # create a uniqe segment id, supports max 10 segments per annotation |
||||
'annotation_id': ann['id'], |
||||
'points': str(seg)[1:-1], |
||||
} |
||||
|
||||
cur.executemany(''' |
||||
INSERT OR IGNORE INTO segments(id, annotation_id, points) |
||||
VALUES (:id, :annotation_id, :points) |
||||
''', segment_generator()) |
||||
con.commit() |
||||
|
||||
|
||||
logger.info("Done...") |
||||
|
||||
# for id, cat in coco.cats.items(): |
||||
# cur = con.cursor() |
||||
# cur.execute |
@ -0,0 +1,234 @@
@@ -0,0 +1,234 @@
|
||||
|
||||
//////////////////////////
|
||||
// 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')+"</"+this.name+">"; |
||||
} 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(); |
@ -0,0 +1,127 @@
@@ -0,0 +1,127 @@
|
||||
|
||||
//////////////////////////
|
||||
// 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')+"</"+this.name+">"; |
||||
} else { |
||||
return "<"+this.name+attrs+"/>" |
||||
} |
||||
} |
||||
//////////// end of faked dom ///////////////////////////////
|
||||
|
||||
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(10).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(7).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().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(name, color) { |
||||
let hash = name+'-'+color; |
||||
if(!textureMap.hasOwnProperty(hash)) { |
||||
let i = Object.keys(textureMap).length; |
||||
textureMap[hash] = getColoredTexture(i, color); |
||||
} |
||||
|
||||
return textureMap[hash]; |
||||
} |
||||
|
||||
|
||||
// turn HTMLCollection into Array, to prevent dynamic updating of the collection during loop
|
||||
pathEls = Array.from(document.getElementsByTagName('path')); |
||||
for(pathEl of pathEls){ |
||||
let defsEls = pathEl.parentNode.getElementsByTagName('defs'); |
||||
let defsEl; |
||||
if(defsEls.length < 1) { |
||||
defsEl = document.createElement("DEFS"); |
||||
pathEl.parentNode.appendChild(defsEl); |
||||
} else { |
||||
defsEl = defsEls[0]; |
||||
} |
||||
|
||||
console.log(pathEl,pathEl.classList); |
||||
if(pathEl.classList.length != 2) continue; |
||||
let super_name = pathEl.classList.item(0).substr(6); |
||||
let cat_name = pathEl.classList.item(1).substr(4); |
||||
let color = getColorForSuperCategory(super_name) |
||||
let texture = getTextureForCategory(cat_name, color); |
||||
|
||||
if(!defsEl.parentNode.getElementById(texture.id())) { |
||||
let sel = new dom(); |
||||
texture(sel); |
||||
console.log(sel, sel.toString()) |
||||
defsEl.innerHTML += sel.toString(); |
||||
} |
||||
|
||||
pathEl.style.fill = texture.url(); |
||||
} |
@ -0,0 +1,47 @@
@@ -0,0 +1,47 @@
|
||||
!function(n,e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):n.crel=e()}(this,function(){function n(a){var d,s=arguments,p=s[1],y=2,m=s.length,x=n[o];if(a=n[u](a)?a:c.createElement(a),m>1){if((!e(p,r)||n[f](p)||Array.isArray(p))&&(--y,p=null),m-y==1&&e(s[y],"string"))a.textContent=s[y];else for(;y<m;++y)null!==(d=s[y])&&l(a,d);for(var v in p)if(x[v]){var A=x[v];e(A,t)?A(a,p[v]):a[i](A,p[v])}else e(p[v],t)?a[v]=p[v]:a[i](v,p[v])}return a}var e=function(n,e){return typeof n===e},t="function",r="object",i="setAttribute",o="attrMap",f="isNode",u="isElement",c=document,a=function(n){return n instanceof Node},d=function(n){return n instanceof Element},l=function(e,t){if(Array.isArray(t))return void t.map(function(n){l(e,n)});n[f](t)||(t=c.createTextNode(t)),e.appendChild(t)};return n[o]={},n[u]=d,n[f]=a,e(Proxy,"undefined")||(n.proxy=new Proxy(n,{get:function(e,t){return!(t in n)&&(n[t]=n.bind(null,t)),n[t]}})),n}); |
||||
|
||||
/* |
||||
* Extended CREL, originally for PillowTalk |
||||
* - event listeners with 'on' |
||||
* - Array with 'options' for 'select' |
||||
* - input type 'checkbox' has 'checked_value', which validates as boolean to set checked state |
||||
*/ |
||||
|
||||
// for input type checkbox, map value to a checkbox
|
||||
crel.attrMap['checked_value'] = function(element, value) { |
||||
if(value) { |
||||
element.checked = 'checked'; |
||||
} |
||||
}; |
||||
crel.attrMap['on'] = function(element, value) { |
||||
for (var eventName in value) { |
||||
element.addEventListener(eventName, value[eventName]); |
||||
} |
||||
}; |
||||
crel.attrMap['options'] = function(element, values, a, b) { |
||||
if(element.tagName != "SELECT") { |
||||
return; |
||||
} |
||||
|
||||
|
||||
let selectedValue = element.value ? element.value : element.attributes.value.value; |
||||
|
||||
if(Array.isArray(values)) { |
||||
for (let option of values) { |
||||
if(selectedValue == option) { |
||||
element.appendChild(crel('option', {'selected': 'selected'}, option)); |
||||
} else { |
||||
element.appendChild(crel('option', option)); |
||||
} |
||||
} |
||||
} else { |
||||
for (let option in values) { |
||||
if(selectedValue == option) { |
||||
element.appendChild(crel('option', {'selected': 'selected','value': option}, values[option])); |
||||
}else{ |
||||
element.appendChild(crel('option', {'value': option}, values[option])); |
||||
} |
||||
} |
||||
} |
||||
|
||||
}; |
File diff suppressed because one or more lines are too long
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
<html> |
||||
<head> |
||||
<meta charset='utf-8'> |
||||
<style type='text/css'> |
||||
body{ |
||||
font-family:sans-serif; |
||||
background: darkblue; |
||||
margin:0; |
||||
} |
||||
|
||||
#svgCanvas{ |
||||
width:100vw; |
||||
height:100vh; |
||||
} |
||||
#catNav{ |
||||
position:absolute; |
||||
top:0; |
||||
left:0; |
||||
color:white; |
||||
} |
||||
#catNav ul{ |
||||
list-style:none; |
||||
padding:10px; |
||||
} |
||||
#catNav li:hover{ |
||||
cursor:pointer; |
||||
text-decoration:underline; |
||||
} |
||||
|
||||
g{ |
||||
cursor:grab; |
||||
} |
||||
|
||||
g:active{ |
||||
cursor:grabbing; |
||||
} |
||||
</style> |
||||
</head> |
||||
<body> |
||||
<nav id='catNav'> |
||||
</nav> |
||||
<svg |
||||
id='svgCanvas' |
||||
xmlns="http://www.w3.org/2000/svg" |
||||
xmlns:ev="http://www.w3.org/2001/xml-events" |
||||
xmlns:xlink="http://www.w3.org/1999/xlink" |
||||
viewBox="0 0 1000 1000"> |
||||
</svg> |
||||
|
||||
|
||||
<!-- <script src="svg-inject.min.js"></script> --> |
||||
<script src="textures.js"></script> |
||||
<script src="crel.min.js"></script> |
||||
<script src="coco.js"></script> |
||||
</body> |
||||
</html> |
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
!function(o,l){var r,a,s="createElement",g="getElementsByTagName",b="length",E="style",d="title",y="undefined",k="setAttribute",w="getAttribute",x=null,A="__svgInject",C="--inject-",S=new RegExp(C+"\\d+","g"),I="LOAD_FAIL",t="SVG_NOT_SUPPORTED",L="SVG_INVALID",v=["src","alt","onload","onerror"],j=l[s]("a"),G=typeof SVGRect!=y,f={useCache:!0,copyAttributes:!0,makeIdsUnique:!0},N={clipPath:["clip-path"],"color-profile":x,cursor:x,filter:x,linearGradient:["fill","stroke"],marker:["marker", |
||||
"marker-end","marker-mid","marker-start"],mask:x,pattern:["fill","stroke"],radialGradient:["fill","stroke"]},u=1,c=2,O=1;function T(e){return(r=r||new XMLSerializer).serializeToString(e)}function P(e,r){var t,n,i,o,a=C+O++,f=/url\("?#([a-zA-Z][\w:.-]*)"?\)/g,u=e.querySelectorAll("[id]"),c=r?[]:x,l={},s=[],d=!1;if(u[b]){for(i=0;i<u[b];i++)(n=u[i].localName)in N&&(l[n]=1);for(n in l)(N[n]||[n]).forEach(function(e){s.indexOf(e)<0&&s.push(e)});s[b]&&s.push(E);var v,p,m,h=e[g]("*"),y=e;for(i=-1;y!=x; |
||||
){if(y.localName==E)(m=(p=y.textContent)&&p.replace(f,function(e,r){return c&&(c[r]=1),"url(#"+r+a+")"}))!==p&&(y.textContent=m);else if(y.hasAttributes()){for(o=0;o<s[b];o++)v=s[o],(m=(p=y[w](v))&&p.replace(f,function(e,r){return c&&(c[r]=1),"url(#"+r+a+")"}))!==p&&y[k](v,m);["xlink:href","href"].forEach(function(e){var r=y[w](e);/^\s*#/.test(r)&&(r=r.trim(),y[k](e,r+a),c&&(c[r.substring(1)]=1))})}y=h[++i]}for(i=0;i<u[b];i++)t=u[i],c&&!c[t.id]||(t.id+=a,d=!0)}return d}function V(e,r,t,n){if(r){ |
||||
r[k]("data-inject-url",t);var i=e.parentNode;if(i){n.copyAttributes&&function c(e,r){for(var t,n,i,o=e.attributes,a=0;a<o[b];a++)if(n=(t=o[a]).name,-1==v.indexOf(n))if(i=t.value,n==d){var f,u=r.firstElementChild;u&&u.localName.toLowerCase()==d?f=u:(f=l[s+"NS"]("http://www.w3.org/2000/svg",d),r.insertBefore(f,u)),f.textContent=i}else r[k](n,i)}(e,r);var o=n.beforeInject,a=o&&o(e,r)||r;i.replaceChild(a,e),e[A]=u,m(e);var f=n.afterInject;f&&f(e,a)}}else D(e,n)}function p(){for(var e={},r=arguments, |
||||
t=0;t<r[b];t++){var n=r[t];for(var i in n)n.hasOwnProperty(i)&&(e[i]=n[i])}return e}function _(e,r){if(r){var t;try{t=function i(e){return(a=a||new DOMParser).parseFromString(e,"text/xml")}(e)}catch(o){return x}return t[g]("parsererror")[b]?x:t.documentElement}var n=l.createElement("div");return n.innerHTML=e,n.firstElementChild}function m(e){e.removeAttribute("onload")}function n(e){console.error("SVGInject: "+e)}function i(e,r,t){e[A]=c,t.onFail?t.onFail(e,r):n(r)}function D(e,r){m(e),i(e,L,r) |
||||
}function F(e,r){m(e),i(e,t,r)}function M(e,r){i(e,I,r)}function q(e){e.onload=x,e.onerror=x}function R(e){n("no img element")}var e=function z(e,r){var t=p(f,r),h={};function n(a,f){f=p(t,f);var e=function(r){var e=function(){var e=f.onAllFinish;e&&e(),r&&r()};if(a&&typeof a[b]!=y){var t=0,n=a[b];if(0==n)e();else for(var i=function(){++t==n&&e()},o=0;o<n;o++)u(a[o],f,i)}else u(a,f,e)};return typeof Promise==y?e():new Promise(e)}function u(u,c,e){if(u){var r=u[A];if(r)Array.isArray(r)?r.push(e |
||||
):e();else{if(q(u),!G)return F(u,c),void e();var t=c.beforeLoad,n=t&&t(u)||u[w]("src");if(!n)return""===n&&M(u,c),void e();var i=[];u[A]=i;var l=function(){e(),i.forEach(function(e){e()})},s=function f(e){return j.href=e,j.href}(n),d=c.useCache,v=c.makeIdsUnique,p=function(r){d&&(h[s].forEach(function(e){e(r)}),h[s]=r)};if(d){var o,a=function(e){if(e===I)M(u,c);else if(e===L)D(u,c);else{var r,t=e[0],n=e[1],i=e[2];v&&(t===x?(t=P(r=_(n,!1),!1),e[0]=t,e[2]=t&&T(r)):t&&(n=function o(e){ |
||||
return e.replace(S,C+O++)}(i))),r=r||_(n,!1),V(u,r,s,c)}l()};if(typeof(o=h[s])!=y)return void(o.isCallbackQueue?o.push(a):a(o));(o=[]).isCallbackQueue=!0,h[s]=o}!function m(e,r,t){if(e){var n=new XMLHttpRequest;n.onreadystatechange=function(){if(4==n.readyState){var e=n.status;200==e?r(n.responseXML,n.responseText.trim()):400<=e?t():0==e&&t()}},n.open("GET",e,!0),n.send()}}(s,function(e,r){var t=e instanceof Document?e.documentElement:_(r,!0),n=c.afterLoad;if(n){var i=n(t,r)||t;if(i){ |
||||
var o="string"==typeof i;r=o?i:T(t),t=o?_(i,!0):i}}if(t instanceof SVGElement){var a=x;if(v&&(a=P(t,!1)),d){var f=a&&T(t);p([a,r,f])}V(u,t,s,c)}else D(u,c),p(L);l()},function(){M(u,c),p(I),l()})}}else R()}return G&&function i(e){var r=l[g]("head")[0];if(r){var t=l[s](E);t.type="text/css",t.appendChild(l.createTextNode(e)),r.appendChild(t)}}('img[onload^="'+e+'("]{visibility:hidden;}'),n.setOptions=function(e){t=p(t,e)},n.create=z,n.err=function(e,r){e?e[A]!=c&&(q(e),G?(m(e),M(e,t)):F(e,t),r&&(m( |
||||
e),e.src=r)):R()},o[e]=n}("SVGInject");"object"==typeof module&&"object"==typeof module.exports&&(module.exports=e)}(window,document); |
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue