From 4fd737e3e1df5ed979a4850f149c9f212ffd2b55 Mon Sep 17 00:00:00 2001 From: Is Isilon Date: Sun, 15 Nov 2015 10:08:32 +0800 Subject: [PATCH] init --- 2c_css_svgs.css | 43 + back.svg | 2384 +++++++++++++++++++++++++++++++ bottom.svg | 2384 +++++++++++++++++++++++++++++++ bower.json | 16 + convert.sh | 6 + front.svg | 2469 ++++++++++++++++++++++++++++++++ grass.png | Bin 0 -> 14970 bytes grass.svg | 2612 ++++++++++++++++++++++++++++++++++ left.svg | 2439 +++++++++++++++++++++++++++++++ manual_good_30.png | Bin 0 -> 29832 bytes manual_good_30.svg | 41 + manualcss2.png | Bin 0 -> 30312 bytes manualcss2.svg | 56 + projectSVG (3rd copy).js | 457 ++++++ projectSVG (another copy).js | 477 +++++++ projectSVG (copy).js | 458 ++++++ projectSVG.js | 477 +++++++ rasterise.js | 48 + right.svg | 2439 +++++++++++++++++++++++++++++++ svg-stylesheet.css | 43 + test.html | 56 + test2.html | 97 ++ top.svg | 2384 +++++++++++++++++++++++++++++++ webdriver_rasterize.js | 52 + 24 files changed, 19438 insertions(+) create mode 100644 2c_css_svgs.css create mode 100644 back.svg create mode 100644 bottom.svg create mode 100644 bower.json create mode 100644 convert.sh create mode 100644 front.svg create mode 100644 grass.png create mode 100644 grass.svg create mode 100644 left.svg create mode 100644 manual_good_30.png create mode 100644 manual_good_30.svg create mode 100644 manualcss2.png create mode 100644 manualcss2.svg create mode 100644 projectSVG (3rd copy).js create mode 100644 projectSVG (another copy).js create mode 100644 projectSVG (copy).js create mode 100644 projectSVG.js create mode 100644 rasterise.js create mode 100644 right.svg create mode 100644 svg-stylesheet.css create mode 100644 test.html create mode 100644 test2.html create mode 100644 top.svg create mode 100644 webdriver_rasterize.js diff --git a/2c_css_svgs.css b/2c_css_svgs.css new file mode 100644 index 0000000..271b9f1 --- /dev/null +++ b/2c_css_svgs.css @@ -0,0 +1,43 @@ + +.grass { + background-image: url(2c_css_svgs.png); + background-position: 0px 0px; + width: 256px; + height: 256px; +} + +.manual_good_30 { + background-image: url(2c_css_svgs.png); + background-position: 0px -256px; + width: 1128px; + height: 1128px; +} + +.manualcss_v2 { + background-image: url(2c_css_svgs.png); + background-position: 0px -431px; + width: 1128px; + height: 1128px; +} + +.manualcss_v2c { + background-image: url(2c_css_svgs.png); + background-position: 0px -606px; + width: 1128px; + height: 1128px; +} + +.manualcss_v2d { + background-image: url(2c_css_svgs.png); + background-position: 0px -1734px; + width: 1128px; + height: 1128px; +} + +.manuallcss_2b { + background-image: url(2c_css_svgs.png); + background-position: 0px -2862px; + width: 1128px; + height: 1128px; +} + diff --git a/back.svg b/back.svg new file mode 100644 index 0000000..e1b67bc --- /dev/null +++ b/back.svg @@ -0,0 +1,2384 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/bottom.svg b/bottom.svg new file mode 100644 index 0000000..e1b67bc --- /dev/null +++ b/bottom.svg @@ -0,0 +1,2384 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..5d62050 --- /dev/null +++ b/bower.json @@ -0,0 +1,16 @@ +{ + "name": "2c_css_svgs", + "description": "", + "main": "", + "moduleType": [], + "license": "Unlicences", + "homepage": "", + "private": true, + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ] +} diff --git a/convert.sh b/convert.sh new file mode 100644 index 0000000..b595bcd --- /dev/null +++ b/convert.sh @@ -0,0 +1,6 @@ +cairosvg manual_good_30.svg -o manual_good_30.png + + +for i in *.svg; do cairosvg $i -o `echo $i | sed -e 's/\.svg$/1.png/'`; done +for i in *.svg; do rsvg-convert -a $i -o `echo $i | sed -e 's/\.svg$/2.png/'`; done +for i in *.svg; do phantomjs rasterise.js $i `echo $i | sed -e 's/\.svg$/3.png/'`; done diff --git a/front.svg b/front.svg new file mode 100644 index 0000000..6c383d5 --- /dev/null +++ b/front.svg @@ -0,0 +1,2469 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/grass.png b/grass.png new file mode 100644 index 0000000000000000000000000000000000000000..14c5c7da1990eb83708e06788d37e092ab30bd77 GIT binary patch literal 14970 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/left.svg b/left.svg new file mode 100644 index 0000000..b87a0ff --- /dev/null +++ b/left.svg @@ -0,0 +1,2439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/manual_good_30.png b/manual_good_30.png new file mode 100644 index 0000000000000000000000000000000000000000..cbbdff97e2402a1c84dd56eb1108289e9ab93137 GIT binary patch literal 29832 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 literal 0 HcmV?d00001 diff --git a/manual_good_30.svg b/manual_good_30.svg new file mode 100644 index 0000000..2991222 --- /dev/null +++ b/manual_good_30.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + diff --git a/manualcss2.png b/manualcss2.png new file mode 100644 index 0000000000000000000000000000000000000000..b577087ef484a73e1e00c90c8d396f3887d62f06 GIT binary patch literal 30312 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�Xem~YAg;#xOPIb!0JYI>lY<%Y;?jJO{coDnJ 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 + https://en.wikipedia.org/wiki/Isometric_projection + + + + + + + + + + + diff --git a/projectSVG (3rd copy).js b/projectSVG (3rd copy).js new file mode 100644 index 0000000..33017ed --- /dev/null +++ b/projectSVG (3rd copy).js @@ -0,0 +1,457 @@ +'use strict'; + +try{ + var Snap = require('snapsvg'); +} catch(e) {}; +var SvgCube = function (options) { + + // Inputs and options + var defaultOptions = { + angle: 30, + size: 64, + verbose: false, + // outline + drawOutline: true, + drawShading: true, + clipCircle: false, + stroke: { + "arrow-end": 'none', + "stroke": 'black', // stroke color for outline + "stroke-width": Math.sqrt(options.size)/2, // outline width + "stroke-linecap": "round", + "stroke-linejoin": "round", + "fill": "none", + }, + // cube + flatten: 0, // fraction to vertically flatten the cube + topUrl: '', // url for image in top of cuve + topRot: 0, // rotation of top image in degrees + topShad: 0, // shading for top + leftUrl: '', + leftRot: 0, + leftShad: 0.1, + rightUrl: '', + rightRot: 0, + rightShad: 0.3, + svgNS: "http://www.w3.org/2000/svg", + padding: 0, + } + + // add defaults, 2 levels deep + options = options || {}; + for (var opt in defaultOptions){ + if (defaultOptions.hasOwnProperty(opt) && !options.hasOwnProperty(opt)){ + options[opt] = defaultOptions[opt]; + } + for (var opt2 in defaultOptions[opt]){ + if (defaultOptions[opt].hasOwnProperty(opt2) && !options[opt].hasOwnProperty(opt2)){ + options[opt][opt2] = defaultOptions[opt][opt2]; + } + } + } + this.options = options + + this.angle = options.angle + + this.w = options.size; // input image width + this.h = options.size; + this.f = options.flatten + + this.rot = this.angle * Math.PI / 180 + this.padding = options.padding; // pading fraction + + + this.cw = this.w; // we will keep same width but change height + this.ch = (1 + this.padding) * (this.h / 2 + this.h * Math.tan(this.rot)) -this.h/2*(1-this.f); //canvas height full + + // create SVG element + this.paper = Snap(this.cw, this.ch); + this.svg=this.paper.node + var o = this.options; + + var style = document.createElement('style'); + this.paper.defs.appendChild(style) + var styleStr = ` ` + console.log(styleStr); + style.innerHTML= styleStr + +} + +/* drawing measurements as a function of padding */ +SvgCube.prototype.measurements= function(p){ + if (p===undefined){ + p=0; + } + + var f = this.options.flatten + + var tBox = this.imageT.getBBox() + var lBox = this.imageL.getBBox() + var rBox = this.imageR.getBBox() + + return { + // measurements + uf : 1-f, + p : 0, // lw/2, // padding + + tw: this.cw-p/2, // right side. adjust by half line thickness to keep line in canvas + th: tBox.height-p/2, // height of square, and dist to middle + + mw: this.cw/2, // middle x + mh: tBox.height/2, // middle of top square + + bh: 0+p/2, // top of picture, bottom y + bw: 0+p/2, // left of picture, bottom of x + + sw: this.cw-p/2,// bottom of cube + sh: this.ch-p/2, // right of cube + + lq: -tBox.height/2+this.ch-p/2, // lower quarter of height + uq: tBox.height/2+p/2 // upper quarter + } +} + + +/* + * Adds a svg transform to an element, the transform has the origin of + * xi,yi fraction of the element, so 0.5,0.5 is the middle, + * unlike normalsvg it adds transforms in order of application not reverse order + * Usage: svgTransform(elementImage,'rotate',[45],0.5,0.5) + * This would rotate 45 degrees around center of image + */ +SvgCube.prototype.svgTransform = function (element, op, inputs, xi, yi) { + if (isNaN(xi)) { + xi = 0.5; + } + if (isNaN(yi)) { + yi = 0.5; + } + var svgBox = this.svg.getClientRects()[0] + // this.paper.getBBox() + var cbox = element.getBoundingClientRect(); + var x = cbox.left + xi * cbox.width -svgBox.left; + var y = cbox.top + yi * cbox.height -svgBox.top; + // + var matrix = this.svg.createSVGMatrix() + matrix = matrix.translate(x, y) + matrix = matrix[op].apply(matrix, inputs); + matrix = matrix.translate(-x, -y); + + var transform = this.svg.createSVGTransform(); + transform.setMatrix(matrix); + //element.transform.baseVal.appendItem(transform); // for reverse order + element.transform.baseVal.insertItemBefore(transform, 0) // normal order +} + +/* + * transform an element to be the left of an isometric cube + * Inputs: dom element, angle in degrees, and xi,yi which + * are the transform origin as a fraction of element size + */ +SvgCube.prototype.toLeft = function (element, angle, xi, yi) { + // half it's width + xi = 0 + yi = 1 + if (this.f>0){ + this.svgTransform(element, 'scaleNonUniform', [1,this.f],0.5,0.5) + } + this.svgTransform(element, 'translate', [-1, -1]) // pixel adjustment HACK + this.svgTransform(element, 'scaleNonUniform', [1 / 2, 1 / 2], xi, yi) + // skew it, in degrees + this.svgTransform(element, 'skewY', [angle], xi, yi) + +} + +/* + * transform an element to be the right of an isometric cube + * Inputs: dom element, angle in degrees, and xi,yi which + * are the transform origin as a fraction of element size + */ +SvgCube.prototype.toRight = function (element, angle, xi, yi) { + xi = 1 + yi = 1 + if (this.f>0){ + this.svgTransform(element, 'scaleNonUniform', [1,this.f],0.5,0.5) + } + this.svgTransform(element, 'translate', [-1, -2]) // pixel adjustment HACK + // half it's width to fiit in canvas + this.svgTransform(element, 'scaleNonUniform', [1 / 2, 1 / 2], xi, yi) + // skew it + this.svgTransform(element, 'skewY', [-angle], xi, yi) + +} + +/* + * transform an element to be the top of an isometric cube + * Inputs: dom element, angle in degrees, and xi,yi which + * are the transform origin as a fraction of element size + */ +SvgCube.prototype.toTop = function (element, angle, xi, yi) { + var rot = angle * Math.PI / 180; + this.svgTransform(element, 'translate', [-2, -1]) // pixel adjustment HACK + + // rotate so it's a diamond + this.svgTransform(element, 'rotate', [45], xi, yi) + // squish - along x axis to fit in canvas, along y axis for perspective change + this.svgTransform(element, 'scaleNonUniform', [Math.sin(45 * Math.PI / 180), Math.tan(rot) * Math.sin(45 * Math.PI / 180)], xi, yi) +} + +SvgCube.prototype.moveTop = function (element) { + // align top of cube with top of canvas + var cbox = element.getBoundingClientRect(); + this.svgTransform(element, 'translate', [-cbox.left + this.pPx, -cbox.top + this.pPx]) +} + +/* + * align left of cube with top, + * fit upper-left of left panel with middle-left of top panel + */ +SvgCube.prototype.moveLeft = function (elem, elemT) { + var cboxL = elem.getBoundingClientRect(); + var cboxT = elemT.getBoundingClientRect(); + // align left + var x = cboxT.left - cboxL.left + // align top of left with half height of + var y = cboxT.top - cboxL.top + cboxT.height / 2 + this.svgTransform(elem, 'translate', [x, y]) +} + +/* + * align right of cube with top, + * fit upper-right of right panel with middle-right of top panel + */ +SvgCube.prototype.moveRight = function (elem, elemT) { + // line up left with top, move to half tops height, and to align left + var cboxL = elem.getBoundingClientRect(); + var cboxT = elemT.getBoundingClientRect(); + + // align right with right + var x = cboxT.right - cboxL.right + + // align top of left with half height of + var y = cboxT.top - cboxL.top + cboxT.height / 2 + this.svgTransform(elem, 'translate', [x, y]) +} + +/* draw outline get line color from option.strokeColor, and width from options.stroke-width */ +SvgCube.prototype.drawOutline = function(lw){ + lw=lw||this.options.stroke["stroke-width"]; + var ms = this.measurements(lw/2) + + + var tb = this.imageT.getBBox() + var lb = this.imageL.getBBox() + var rb = this.imageR.getBBox() + + // Draw outline of top + var strTop= + 'M'+ms.mw +' '+ms.th +' '+ // Move to bottom + 'L'+ms.bw +' '+ms.mh+' '+ // left + 'L'+ms.mw +' '+ms.bh+ ' '+ // top + 'L'+ms.tw +' '+ms.mh+' '+ // right + 'Z' // close + var pathTop = this.paper.path(strTop); + + // // outline of left + var strLeft= + 'M'+ms.mw +' '+ms.th+' '+ // middle + 'L'+ms.bw +' '+ms.uq+' '+ // left top + 'L'+ms.bw +' '+ms.lq+' '+ // left bottom + 'L'+ms.mw +' '+ms.sh+' '+ // middle bottom + 'Z' + var pathLeft = this.paper.path(strLeft); + // + // right + var strRight= + 'M'+ms.mw +' '+ms.th+' '+ // middle + 'L'+ms.mw +' '+ms.sh +' '+ // middle bottom + 'L'+ms.tw +' '+ms.lq+' '+ // right bottom + 'L'+ms.tw +' '+ms.uq+' '+ // right top + 'Z' // close + var pathRight = this.paper.path(strRight); + + // join into set + var pathGroup = this.paper.group(); + pathGroup.append(pathTop); + pathGroup.append(pathLeft); + pathGroup.append(pathRight); + + // set attrs from options + // ref http://raphaeljs.com/reference.html#Element.attr + var blackList = ['url','target','src','title'] + for (var a in this.options.stroke){ + if (this.options.stroke.hasOwnProperty(a) && blackList.indexOf(a)<0){ + pathGroup.attr(a,this.options.stroke[a]); + } + } + this.outline=pathGroup; +} + + +/* draw outline get line color from option.strokeColor, and width from options.stroke-width */ +SvgCube.prototype.drawShading = function(lw){ + lw=lw||this.options.stroke["stroke-width"]; + var ms = this.measurements(0); + var pathGroup = this.paper.g(); + + var strTop= + 'M'+ms.mw +' '+ms.th +' '+ // Move to bottom + 'L'+ms.bw +' '+ms.mh+' '+ // left + 'L'+ms.mw +' '+ms.bh+ ' '+ // top + 'L'+ms.tw +' '+ms.mh+' '+ // right + 'Z' // close + var pathTop = this.paper.path(strTop); + pathGroup.append(pathTop); + + // outline of left + var strLeft= + 'M'+ms.mw +' '+ms.th+' '+ // middle + 'L'+ms.bw +' '+ms.uq+' '+ // left top + 'L'+ms.bw +' '+ms.lq+' '+ // left bottom + 'L'+ms.mw +' '+ms.sh+' '+ // middle bottom + 'Z' + var pathLeft = this.paper.path(strLeft); + pathGroup.append(pathLeft); + + // last line from middle down + var strRight= + 'M'+ms.mw +' '+ms.th+' '+ // middle + 'L'+ms.mw +' '+ms.sh +' '+ // middle bottom + 'L'+ms.tw +' '+ms.lq+' '+ // right bottom + 'L'+ms.tw +' '+ms.uq+' '+ // right top + 'Z' // close + var pathRight = this.paper.path(strRight); + pathGroup.append(pathRight); + + + // style the set + pathGroup.attr({ + 'stroke': 'none', + 'fill': 'black', + 'stroke-width': 0, + 'stroke-opacity': 0, + 'stroke-linecap': 'round', + 'stroke-linejoin': 'round' + }); + // shade each side, 0 is no shading, 1 is black + pathTop.attr({'fill-opacity': this.options.topShad}); + pathLeft.attr({'fill-opacity': this.options.leftShad}); + pathRight.attr({'fill-opacity': this.options.rightShad}); + this.shading=pathGroup; + +} + +/*clip the cube using an elipse to give rounded corners */ +SvgCube.prototype.clipCircle = function(amount){ + var cp = document.createElementNS("http://www.w3.org/2000/svg","clipPath") + cp.id="cp"; + var rxc=51+4*(1-this.f)*(1-this.f); + var ryc=50-2/Math.sqrt(1-this.f); + cp.innerHTML = '' + this.paper.node.getElementsByTagName("defs")[0].appendChild(cp); + this.paper.node.setAttribute("clip-path","url(#cp)"); +} + + +/* returns svg string */ +SvgCube.prototype.toSVG = function(){ + var svg3 = this.paper.toString(); + //var svg = this.paper.node.outerHTML; + //var svg2 = xmlserializer.serializeToString(this.paper.node); + if (this.paper.node.attributes.getNamedItem("clip-path")){ + // patch svg export to add clip + // HACK I have to add these manually to the export sadly as raphael.export doesn't handle them and also misses some recent change to canvas + svg3=svg3.replace(" + .cube, .cube .face, .cube .face * { + height: ${o.size}px; + width: ${o.size}px; + } + .cube { + position: absolute; + background-color: #f66; + + -webkit-transform: translate(${this.cw/2}px,${0*this.ch/2}px) perspective(${o.perspective}px) rotateX(${o.angle}deg) rotateX(${o.rotateX}deg) rotateY(${o.rotateY}deg) rotateZ(${o.rotateZ}deg); + -webkit-transform-style: preserve-3d; + -webkit-transition: .25s; + } + + + .cube * { + transform-origin: 0% 100%; + } + + .cube2 .top { + position: relative; + -webkit-transform: rotateX(45deg) rotateZ(-45deg) rotateX(0deg); + -webkit-transform-style: preserve-3d; + -webkit-transition: .25s; + + } + .cube2 .left { + -webkit-transform: rotateX(45deg) rotateZ(-45deg) rotateX(90deg); + -webkit-transform-style: preserve-3d; + -webkit-transition: .25s; + position: absolute; + + } + .cube2 .right { + -webkit-transform: rotateX(45deg) rotateZ(-45deg) rotateY(90deg); + -webkit-transform-style: preserve-3d; + -webkit-transition: .25s; + position: absolute; + } + ` + console.log(styleStr); + style.innerHTML= styleStr + +} + +/* drawing measurements as a function of padding */ +SvgCube.prototype.measurements= function(p){ + if (p===undefined){ + p=0; + } + + var f = this.options.flatten + + var tBox = this.imageT.getBBox() + var lBox = this.imageL.getBBox() + var rBox = this.imageR.getBBox() + + return { + // measurements + uf : 1-f, + p : 0, // lw/2, // padding + + tw: this.cw-p/2, // right side. adjust by half line thickness to keep line in canvas + th: tBox.height-p/2, // height of square, and dist to middle + + mw: this.cw/2, // middle x + mh: tBox.height/2, // middle of top square + + bh: 0+p/2, // top of picture, bottom y + bw: 0+p/2, // left of picture, bottom of x + + sw: this.cw-p/2,// bottom of cube + sh: this.ch-p/2, // right of cube + + lq: -tBox.height/2+this.ch-p/2, // lower quarter of height + uq: tBox.height/2+p/2 // upper quarter + } +} + + +/* + * Adds a svg transform to an element, the transform has the origin of + * xi,yi fraction of the element, so 0.5,0.5 is the middle, + * unlike normalsvg it adds transforms in order of application not reverse order + * Usage: svgTransform(elementImage,'rotate',[45],0.5,0.5) + * This would rotate 45 degrees around center of image + */ +SvgCube.prototype.svgTransform = function (element, op, inputs, xi, yi) { + if (isNaN(xi)) { + xi = 0.5; + } + if (isNaN(yi)) { + yi = 0.5; + } + var svgBox = this.svg.getClientRects()[0] + // this.paper.getBBox() + var cbox = element.getBoundingClientRect(); + var x = cbox.left + xi * cbox.width -svgBox.left; + var y = cbox.top + yi * cbox.height -svgBox.top; + // + var matrix = this.svg.createSVGMatrix() + matrix = matrix.translate(x, y) + matrix = matrix[op].apply(matrix, inputs); + matrix = matrix.translate(-x, -y); + + var transform = this.svg.createSVGTransform(); + transform.setMatrix(matrix); + //element.transform.baseVal.appendItem(transform); // for reverse order + element.transform.baseVal.insertItemBefore(transform, 0) // normal order +} + +/* + * transform an element to be the left of an isometric cube + * Inputs: dom element, angle in degrees, and xi,yi which + * are the transform origin as a fraction of element size + */ +SvgCube.prototype.toLeft = function (element, angle, xi, yi) { + // half it's width + xi = 0 + yi = 1 + if (this.f>0){ + this.svgTransform(element, 'scaleNonUniform', [1,this.f],0.5,0.5) + } + this.svgTransform(element, 'translate', [-1, -1]) // pixel adjustment HACK + this.svgTransform(element, 'scaleNonUniform', [1 / 2, 1 / 2], xi, yi) + // skew it, in degrees + this.svgTransform(element, 'skewY', [angle], xi, yi) + +} + +/* + * transform an element to be the right of an isometric cube + * Inputs: dom element, angle in degrees, and xi,yi which + * are the transform origin as a fraction of element size + */ +SvgCube.prototype.toRight = function (element, angle, xi, yi) { + xi = 1 + yi = 1 + if (this.f>0){ + this.svgTransform(element, 'scaleNonUniform', [1,this.f],0.5,0.5) + } + this.svgTransform(element, 'translate', [-1, -2]) // pixel adjustment HACK + // half it's width to fiit in canvas + this.svgTransform(element, 'scaleNonUniform', [1 / 2, 1 / 2], xi, yi) + // skew it + this.svgTransform(element, 'skewY', [-angle], xi, yi) + +} + +/* + * transform an element to be the top of an isometric cube + * Inputs: dom element, angle in degrees, and xi,yi which + * are the transform origin as a fraction of element size + */ +SvgCube.prototype.toTop = function (element, angle, xi, yi) { + var rot = angle * Math.PI / 180; + this.svgTransform(element, 'translate', [-2, -1]) // pixel adjustment HACK + + // rotate so it's a diamond + this.svgTransform(element, 'rotate', [45], xi, yi) + // squish - along x axis to fit in canvas, along y axis for perspective change + this.svgTransform(element, 'scaleNonUniform', [Math.sin(45 * Math.PI / 180), Math.tan(rot) * Math.sin(45 * Math.PI / 180)], xi, yi) +} + +SvgCube.prototype.moveTop = function (element) { + // align top of cube with top of canvas + var cbox = element.getBoundingClientRect(); + this.svgTransform(element, 'translate', [-cbox.left + this.pPx, -cbox.top + this.pPx]) +} + +/* + * align left of cube with top, + * fit upper-left of left panel with middle-left of top panel + */ +SvgCube.prototype.moveLeft = function (elem, elemT) { + var cboxL = elem.getBoundingClientRect(); + var cboxT = elemT.getBoundingClientRect(); + // align left + var x = cboxT.left - cboxL.left + // align top of left with half height of + var y = cboxT.top - cboxL.top + cboxT.height / 2 + this.svgTransform(elem, 'translate', [x, y]) +} + +/* + * align right of cube with top, + * fit upper-right of right panel with middle-right of top panel + */ +SvgCube.prototype.moveRight = function (elem, elemT) { + // line up left with top, move to half tops height, and to align left + var cboxL = elem.getBoundingClientRect(); + var cboxT = elemT.getBoundingClientRect(); + + // align right with right + var x = cboxT.right - cboxL.right + + // align top of left with half height of + var y = cboxT.top - cboxL.top + cboxT.height / 2 + this.svgTransform(elem, 'translate', [x, y]) +} + +/* draw outline get line color from option.strokeColor, and width from options.stroke-width */ +SvgCube.prototype.drawOutline = function(lw){ + lw=lw||this.options.stroke["stroke-width"]; + var ms = this.measurements(lw/2) + + + var tb = this.imageT.getBBox() + var lb = this.imageL.getBBox() + var rb = this.imageR.getBBox() + + // Draw outline of top + var strTop= + 'M'+ms.mw +' '+ms.th +' '+ // Move to bottom + 'L'+ms.bw +' '+ms.mh+' '+ // left + 'L'+ms.mw +' '+ms.bh+ ' '+ // top + 'L'+ms.tw +' '+ms.mh+' '+ // right + 'Z' // close + var pathTop = this.paper.path(strTop); + + // // outline of left + var strLeft= + 'M'+ms.mw +' '+ms.th+' '+ // middle + 'L'+ms.bw +' '+ms.uq+' '+ // left top + 'L'+ms.bw +' '+ms.lq+' '+ // left bottom + 'L'+ms.mw +' '+ms.sh+' '+ // middle bottom + 'Z' + var pathLeft = this.paper.path(strLeft); + // + // right + var strRight= + 'M'+ms.mw +' '+ms.th+' '+ // middle + 'L'+ms.mw +' '+ms.sh +' '+ // middle bottom + 'L'+ms.tw +' '+ms.lq+' '+ // right bottom + 'L'+ms.tw +' '+ms.uq+' '+ // right top + 'Z' // close + var pathRight = this.paper.path(strRight); + + // join into set + var pathGroup = this.paper.group(); + pathGroup.append(pathTop); + pathGroup.append(pathLeft); + pathGroup.append(pathRight); + + // set attrs from options + // ref http://raphaeljs.com/reference.html#Element.attr + var blackList = ['url','target','src','title'] + for (var a in this.options.stroke){ + if (this.options.stroke.hasOwnProperty(a) && blackList.indexOf(a)<0){ + pathGroup.attr(a,this.options.stroke[a]); + } + } + this.outline=pathGroup; +} + + +/* draw outline get line color from option.strokeColor, and width from options.stroke-width */ +SvgCube.prototype.drawShading = function(lw){ + lw=lw||this.options.stroke["stroke-width"]; + var ms = this.measurements(0); + var pathGroup = this.paper.g(); + + var strTop= + 'M'+ms.mw +' '+ms.th +' '+ // Move to bottom + 'L'+ms.bw +' '+ms.mh+' '+ // left + 'L'+ms.mw +' '+ms.bh+ ' '+ // top + 'L'+ms.tw +' '+ms.mh+' '+ // right + 'Z' // close + var pathTop = this.paper.path(strTop); + pathGroup.append(pathTop); + + // outline of left + var strLeft= + 'M'+ms.mw +' '+ms.th+' '+ // middle + 'L'+ms.bw +' '+ms.uq+' '+ // left top + 'L'+ms.bw +' '+ms.lq+' '+ // left bottom + 'L'+ms.mw +' '+ms.sh+' '+ // middle bottom + 'Z' + var pathLeft = this.paper.path(strLeft); + pathGroup.append(pathLeft); + + // last line from middle down + var strRight= + 'M'+ms.mw +' '+ms.th+' '+ // middle + 'L'+ms.mw +' '+ms.sh +' '+ // middle bottom + 'L'+ms.tw +' '+ms.lq+' '+ // right bottom + 'L'+ms.tw +' '+ms.uq+' '+ // right top + 'Z' // close + var pathRight = this.paper.path(strRight); + pathGroup.append(pathRight); + + + // style the set + pathGroup.attr({ + 'stroke': 'none', + 'fill': 'black', + 'stroke-width': 0, + 'stroke-opacity': 0, + 'stroke-linecap': 'round', + 'stroke-linejoin': 'round' + }); + // shade each side, 0 is no shading, 1 is black + pathTop.attr({'fill-opacity': this.options.topShad}); + pathLeft.attr({'fill-opacity': this.options.leftShad}); + pathRight.attr({'fill-opacity': this.options.rightShad}); + this.shading=pathGroup; + +} + +/*clip the cube using an elipse to give rounded corners */ +SvgCube.prototype.clipCircle = function(amount){ + var cp = document.createElementNS("http://www.w3.org/2000/svg","clipPath") + cp.id="cp"; + var rxc=51+4*(1-this.f)*(1-this.f); + var ryc=50-2/Math.sqrt(1-this.f); + cp.innerHTML = '' + this.paper.node.getElementsByTagName("defs")[0].appendChild(cp); + this.paper.node.setAttribute("clip-path","url(#cp)"); +} + + +/* returns svg string */ +SvgCube.prototype.toSVG = function(){ + var svg3 = this.paper.toString(); + //var svg = this.paper.node.outerHTML; + //var svg2 = xmlserializer.serializeToString(this.paper.node); + if (this.paper.node.attributes.getNamedItem("clip-path")){ + // patch svg export to add clip + // HACK I have to add these manually to the export sadly as raphael.export doesn't handle them and also misses some recent change to canvas + svg3=svg3.replace(" + .cube, .cube .face, .cube .face * { + height: ${o.size}px; + width: ${o.size}px; + } + .cube { + position: absolute; + background-color: #f66; + -webkit-transform: translate(${o.size/2}px,${0}px); + -webkit-transform-style: preserve-3d; + -webkit-transition: .25s; + transform: rotateX(${o.angle}deg) scaleY(${o.flatten}); + } + + .cube * { + transform-origin: 0% 100%; + } + + .cube2 .top { + position: relative; + -webkit-transform: rotateX(45deg) rotateZ(-45deg) rotateX(0deg); + -webkit-transform-style: preserve-3d; + -webkit-transition: .25s; + + } + .cube2 .left { + -webkit-transform: rotateX(45deg) rotateZ(-45deg) rotateX(90deg); + -webkit-transform-style: preserve-3d; + -webkit-transition: .25s; + position: absolute; + + } + .cube2 .right { + -webkit-transform: rotateX(45deg) rotateZ(-45deg) rotateY(90deg); + -webkit-transform-style: preserve-3d; + -webkit-transition: .25s; + position: absolute; + } + ` + console.log(styleStr); + style.innerHTML= styleStr + +} + +/* drawing measurements as a function of padding */ +SvgCube.prototype.measurements= function(p){ + if (p===undefined){ + p=0; + } + + var f = this.options.flatten + + var tBox = this.imageT.getBBox() + var lBox = this.imageL.getBBox() + var rBox = this.imageR.getBBox() + + return { + // measurements + uf : 1-f, + p : 0, // lw/2, // padding + + tw: this.cw-p/2, // right side. adjust by half line thickness to keep line in canvas + th: tBox.height-p/2, // height of square, and dist to middle + + mw: this.cw/2, // middle x + mh: tBox.height/2, // middle of top square + + bh: 0+p/2, // top of picture, bottom y + bw: 0+p/2, // left of picture, bottom of x + + sw: this.cw-p/2,// bottom of cube + sh: this.ch-p/2, // right of cube + + lq: -tBox.height/2+this.ch-p/2, // lower quarter of height + uq: tBox.height/2+p/2 // upper quarter + } +} + + +/* + * Adds a svg transform to an element, the transform has the origin of + * xi,yi fraction of the element, so 0.5,0.5 is the middle, + * unlike normalsvg it adds transforms in order of application not reverse order + * Usage: svgTransform(elementImage,'rotate',[45],0.5,0.5) + * This would rotate 45 degrees around center of image + */ +SvgCube.prototype.svgTransform = function (element, op, inputs, xi, yi) { + if (isNaN(xi)) { + xi = 0.5; + } + if (isNaN(yi)) { + yi = 0.5; + } + var svgBox = this.svg.getClientRects()[0] + // this.paper.getBBox() + var cbox = element.getBoundingClientRect(); + var x = cbox.left + xi * cbox.width -svgBox.left; + var y = cbox.top + yi * cbox.height -svgBox.top; + // + var matrix = this.svg.createSVGMatrix() + matrix = matrix.translate(x, y) + matrix = matrix[op].apply(matrix, inputs); + matrix = matrix.translate(-x, -y); + + var transform = this.svg.createSVGTransform(); + transform.setMatrix(matrix); + //element.transform.baseVal.appendItem(transform); // for reverse order + element.transform.baseVal.insertItemBefore(transform, 0) // normal order +} + +/* + * transform an element to be the left of an isometric cube + * Inputs: dom element, angle in degrees, and xi,yi which + * are the transform origin as a fraction of element size + */ +SvgCube.prototype.toLeft = function (element, angle, xi, yi) { + // half it's width + xi = 0 + yi = 1 + if (this.f>0){ + this.svgTransform(element, 'scaleNonUniform', [1,this.f],0.5,0.5) + } + this.svgTransform(element, 'translate', [-1, -1]) // pixel adjustment HACK + this.svgTransform(element, 'scaleNonUniform', [1 / 2, 1 / 2], xi, yi) + // skew it, in degrees + this.svgTransform(element, 'skewY', [angle], xi, yi) + +} + +/* + * transform an element to be the right of an isometric cube + * Inputs: dom element, angle in degrees, and xi,yi which + * are the transform origin as a fraction of element size + */ +SvgCube.prototype.toRight = function (element, angle, xi, yi) { + xi = 1 + yi = 1 + if (this.f>0){ + this.svgTransform(element, 'scaleNonUniform', [1,this.f],0.5,0.5) + } + this.svgTransform(element, 'translate', [-1, -2]) // pixel adjustment HACK + // half it's width to fiit in canvas + this.svgTransform(element, 'scaleNonUniform', [1 / 2, 1 / 2], xi, yi) + // skew it + this.svgTransform(element, 'skewY', [-angle], xi, yi) + +} + +/* + * transform an element to be the top of an isometric cube + * Inputs: dom element, angle in degrees, and xi,yi which + * are the transform origin as a fraction of element size + */ +SvgCube.prototype.toTop = function (element, angle, xi, yi) { + var rot = angle * Math.PI / 180; + this.svgTransform(element, 'translate', [-2, -1]) // pixel adjustment HACK + + // rotate so it's a diamond + this.svgTransform(element, 'rotate', [45], xi, yi) + // squish - along x axis to fit in canvas, along y axis for perspective change + this.svgTransform(element, 'scaleNonUniform', [Math.sin(45 * Math.PI / 180), Math.tan(rot) * Math.sin(45 * Math.PI / 180)], xi, yi) +} + +SvgCube.prototype.moveTop = function (element) { + // align top of cube with top of canvas + var cbox = element.getBoundingClientRect(); + this.svgTransform(element, 'translate', [-cbox.left + this.pPx, -cbox.top + this.pPx]) +} + +/* + * align left of cube with top, + * fit upper-left of left panel with middle-left of top panel + */ +SvgCube.prototype.moveLeft = function (elem, elemT) { + var cboxL = elem.getBoundingClientRect(); + var cboxT = elemT.getBoundingClientRect(); + // align left + var x = cboxT.left - cboxL.left + // align top of left with half height of + var y = cboxT.top - cboxL.top + cboxT.height / 2 + this.svgTransform(elem, 'translate', [x, y]) +} + +/* + * align right of cube with top, + * fit upper-right of right panel with middle-right of top panel + */ +SvgCube.prototype.moveRight = function (elem, elemT) { + // line up left with top, move to half tops height, and to align left + var cboxL = elem.getBoundingClientRect(); + var cboxT = elemT.getBoundingClientRect(); + + // align right with right + var x = cboxT.right - cboxL.right + + // align top of left with half height of + var y = cboxT.top - cboxL.top + cboxT.height / 2 + this.svgTransform(elem, 'translate', [x, y]) +} + +/* draw outline get line color from option.strokeColor, and width from options.stroke-width */ +SvgCube.prototype.drawOutline = function(lw){ + lw=lw||this.options.stroke["stroke-width"]; + var ms = this.measurements(lw/2) + + + var tb = this.imageT.getBBox() + var lb = this.imageL.getBBox() + var rb = this.imageR.getBBox() + + // Draw outline of top + var strTop= + 'M'+ms.mw +' '+ms.th +' '+ // Move to bottom + 'L'+ms.bw +' '+ms.mh+' '+ // left + 'L'+ms.mw +' '+ms.bh+ ' '+ // top + 'L'+ms.tw +' '+ms.mh+' '+ // right + 'Z' // close + var pathTop = this.paper.path(strTop); + + // // outline of left + var strLeft= + 'M'+ms.mw +' '+ms.th+' '+ // middle + 'L'+ms.bw +' '+ms.uq+' '+ // left top + 'L'+ms.bw +' '+ms.lq+' '+ // left bottom + 'L'+ms.mw +' '+ms.sh+' '+ // middle bottom + 'Z' + var pathLeft = this.paper.path(strLeft); + // + // right + var strRight= + 'M'+ms.mw +' '+ms.th+' '+ // middle + 'L'+ms.mw +' '+ms.sh +' '+ // middle bottom + 'L'+ms.tw +' '+ms.lq+' '+ // right bottom + 'L'+ms.tw +' '+ms.uq+' '+ // right top + 'Z' // close + var pathRight = this.paper.path(strRight); + + // join into set + var pathGroup = this.paper.group(); + pathGroup.append(pathTop); + pathGroup.append(pathLeft); + pathGroup.append(pathRight); + + // set attrs from options + // ref http://raphaeljs.com/reference.html#Element.attr + var blackList = ['url','target','src','title'] + for (var a in this.options.stroke){ + if (this.options.stroke.hasOwnProperty(a) && blackList.indexOf(a)<0){ + pathGroup.attr(a,this.options.stroke[a]); + } + } + this.outline=pathGroup; +} + + +/* draw outline get line color from option.strokeColor, and width from options.stroke-width */ +SvgCube.prototype.drawShading = function(lw){ + lw=lw||this.options.stroke["stroke-width"]; + var ms = this.measurements(0); + var pathGroup = this.paper.g(); + + var strTop= + 'M'+ms.mw +' '+ms.th +' '+ // Move to bottom + 'L'+ms.bw +' '+ms.mh+' '+ // left + 'L'+ms.mw +' '+ms.bh+ ' '+ // top + 'L'+ms.tw +' '+ms.mh+' '+ // right + 'Z' // close + var pathTop = this.paper.path(strTop); + pathGroup.append(pathTop); + + // outline of left + var strLeft= + 'M'+ms.mw +' '+ms.th+' '+ // middle + 'L'+ms.bw +' '+ms.uq+' '+ // left top + 'L'+ms.bw +' '+ms.lq+' '+ // left bottom + 'L'+ms.mw +' '+ms.sh+' '+ // middle bottom + 'Z' + var pathLeft = this.paper.path(strLeft); + pathGroup.append(pathLeft); + + // last line from middle down + var strRight= + 'M'+ms.mw +' '+ms.th+' '+ // middle + 'L'+ms.mw +' '+ms.sh +' '+ // middle bottom + 'L'+ms.tw +' '+ms.lq+' '+ // right bottom + 'L'+ms.tw +' '+ms.uq+' '+ // right top + 'Z' // close + var pathRight = this.paper.path(strRight); + pathGroup.append(pathRight); + + + // style the set + pathGroup.attr({ + 'stroke': 'none', + 'fill': 'black', + 'stroke-width': 0, + 'stroke-opacity': 0, + 'stroke-linecap': 'round', + 'stroke-linejoin': 'round' + }); + // shade each side, 0 is no shading, 1 is black + pathTop.attr({'fill-opacity': this.options.topShad}); + pathLeft.attr({'fill-opacity': this.options.leftShad}); + pathRight.attr({'fill-opacity': this.options.rightShad}); + this.shading=pathGroup; + +} + +/*clip the cube using an elipse to give rounded corners */ +SvgCube.prototype.clipCircle = function(amount){ + var cp = document.createElementNS("http://www.w3.org/2000/svg","clipPath") + cp.id="cp"; + var rxc=51+4*(1-this.f)*(1-this.f); + var ryc=50-2/Math.sqrt(1-this.f); + cp.innerHTML = '' + this.paper.node.getElementsByTagName("defs")[0].appendChild(cp); + this.paper.node.setAttribute("clip-path","url(#cp)"); +} + + +/* returns svg string */ +SvgCube.prototype.toSVG = function(){ + var svg3 = this.paper.toString(); + //var svg = this.paper.node.outerHTML; + //var svg2 = xmlserializer.serializeToString(this.paper.node); + if (this.paper.node.attributes.getNamedItem("clip-path")){ + // patch svg export to add clip + // HACK I have to add these manually to the export sadly as raphael.export doesn't handle them and also misses some recent change to canvas + svg3=svg3.replace(" + .cube, .cube .face, .cube .face * { + height: ${o.size}px; + width: ${o.size}px; + } + .cube { + position: absolute; + background-color: #f66; + + -webkit-transform: translate(${this.cw/2}px,${0*this.ch/2}px) perspective(${o.perspective}px) rotateX(${o.rotateX}deg) rotateY(${o.rotateY}deg) rotateZ(${o.rotateZ}deg); + -webkit-transform-style: preserve-3d; + -webkit-transition: .25s; + } + + + .cube * { + transform-origin: 0% 100%; + } + + .cube2 .top { + position: relative; + -webkit-transform: rotateX(45deg) rotateZ(-45deg) rotateX(0deg); + -webkit-transform-style: preserve-3d; + -webkit-transition: .25s; + + } + .cube2 .left { + -webkit-transform: rotateX(45deg) rotateZ(-45deg) rotateX(90deg); + -webkit-transform-style: preserve-3d; + -webkit-transition: .25s; + position: absolute; + + } + .cube2 .right { + -webkit-transform: rotateX(45deg) rotateZ(-45deg) rotateY(90deg); + -webkit-transform-style: preserve-3d; + -webkit-transition: .25s; + position: absolute; + } + ` + console.log(styleStr); + style.innerHTML= styleStr + +} + +/* drawing measurements as a function of padding */ +SvgCube.prototype.measurements= function(p){ + if (p===undefined){ + p=0; + } + + var f = this.options.flatten + + var tBox = this.imageT.getBBox() + var lBox = this.imageL.getBBox() + var rBox = this.imageR.getBBox() + + return { + // measurements + uf : 1-f, + p : 0, // lw/2, // padding + + tw: this.cw-p/2, // right side. adjust by half line thickness to keep line in canvas + th: tBox.height-p/2, // height of square, and dist to middle + + mw: this.cw/2, // middle x + mh: tBox.height/2, // middle of top square + + bh: 0+p/2, // top of picture, bottom y + bw: 0+p/2, // left of picture, bottom of x + + sw: this.cw-p/2,// bottom of cube + sh: this.ch-p/2, // right of cube + + lq: -tBox.height/2+this.ch-p/2, // lower quarter of height + uq: tBox.height/2+p/2 // upper quarter + } +} + + +/* + * Adds a svg transform to an element, the transform has the origin of + * xi,yi fraction of the element, so 0.5,0.5 is the middle, + * unlike normalsvg it adds transforms in order of application not reverse order + * Usage: svgTransform(elementImage,'rotate',[45],0.5,0.5) + * This would rotate 45 degrees around center of image + */ +SvgCube.prototype.svgTransform = function (element, op, inputs, xi, yi) { + if (isNaN(xi)) { + xi = 0.5; + } + if (isNaN(yi)) { + yi = 0.5; + } + var svgBox = this.svg.getClientRects()[0] + // this.paper.getBBox() + var cbox = element.getBoundingClientRect(); + var x = cbox.left + xi * cbox.width -svgBox.left; + var y = cbox.top + yi * cbox.height -svgBox.top; + // + var matrix = this.svg.createSVGMatrix() + matrix = matrix.translate(x, y) + matrix = matrix[op].apply(matrix, inputs); + matrix = matrix.translate(-x, -y); + + var transform = this.svg.createSVGTransform(); + transform.setMatrix(matrix); + //element.transform.baseVal.appendItem(transform); // for reverse order + element.transform.baseVal.insertItemBefore(transform, 0) // normal order +} + +/* + * transform an element to be the left of an isometric cube + * Inputs: dom element, angle in degrees, and xi,yi which + * are the transform origin as a fraction of element size + */ +SvgCube.prototype.toLeft = function (element, angle, xi, yi) { + // half it's width + xi = 0 + yi = 1 + if (this.f>0){ + this.svgTransform(element, 'scaleNonUniform', [1,this.f],0.5,0.5) + } + this.svgTransform(element, 'translate', [-1, -1]) // pixel adjustment HACK + this.svgTransform(element, 'scaleNonUniform', [1 / 2, 1 / 2], xi, yi) + // skew it, in degrees + this.svgTransform(element, 'skewY', [angle], xi, yi) + +} + +/* + * transform an element to be the right of an isometric cube + * Inputs: dom element, angle in degrees, and xi,yi which + * are the transform origin as a fraction of element size + */ +SvgCube.prototype.toRight = function (element, angle, xi, yi) { + xi = 1 + yi = 1 + if (this.f>0){ + this.svgTransform(element, 'scaleNonUniform', [1,this.f],0.5,0.5) + } + this.svgTransform(element, 'translate', [-1, -2]) // pixel adjustment HACK + // half it's width to fiit in canvas + this.svgTransform(element, 'scaleNonUniform', [1 / 2, 1 / 2], xi, yi) + // skew it + this.svgTransform(element, 'skewY', [-angle], xi, yi) + +} + +/* + * transform an element to be the top of an isometric cube + * Inputs: dom element, angle in degrees, and xi,yi which + * are the transform origin as a fraction of element size + */ +SvgCube.prototype.toTop = function (element, angle, xi, yi) { + var rot = angle * Math.PI / 180; + this.svgTransform(element, 'translate', [-2, -1]) // pixel adjustment HACK + + // rotate so it's a diamond + this.svgTransform(element, 'rotate', [45], xi, yi) + // squish - along x axis to fit in canvas, along y axis for perspective change + this.svgTransform(element, 'scaleNonUniform', [Math.sin(45 * Math.PI / 180), Math.tan(rot) * Math.sin(45 * Math.PI / 180)], xi, yi) +} + +SvgCube.prototype.moveTop = function (element) { + // align top of cube with top of canvas + var cbox = element.getBoundingClientRect(); + this.svgTransform(element, 'translate', [-cbox.left + this.pPx, -cbox.top + this.pPx]) +} + +/* + * align left of cube with top, + * fit upper-left of left panel with middle-left of top panel + */ +SvgCube.prototype.moveLeft = function (elem, elemT) { + var cboxL = elem.getBoundingClientRect(); + var cboxT = elemT.getBoundingClientRect(); + // align left + var x = cboxT.left - cboxL.left + // align top of left with half height of + var y = cboxT.top - cboxL.top + cboxT.height / 2 + this.svgTransform(elem, 'translate', [x, y]) +} + +/* + * align right of cube with top, + * fit upper-right of right panel with middle-right of top panel + */ +SvgCube.prototype.moveRight = function (elem, elemT) { + // line up left with top, move to half tops height, and to align left + var cboxL = elem.getBoundingClientRect(); + var cboxT = elemT.getBoundingClientRect(); + + // align right with right + var x = cboxT.right - cboxL.right + + // align top of left with half height of + var y = cboxT.top - cboxL.top + cboxT.height / 2 + this.svgTransform(elem, 'translate', [x, y]) +} + +/* draw outline get line color from option.strokeColor, and width from options.stroke-width */ +SvgCube.prototype.drawOutline = function(lw){ + lw=lw||this.options.stroke["stroke-width"]; + var ms = this.measurements(lw/2) + + + var tb = this.imageT.getBBox() + var lb = this.imageL.getBBox() + var rb = this.imageR.getBBox() + + // Draw outline of top + var strTop= + 'M'+ms.mw +' '+ms.th +' '+ // Move to bottom + 'L'+ms.bw +' '+ms.mh+' '+ // left + 'L'+ms.mw +' '+ms.bh+ ' '+ // top + 'L'+ms.tw +' '+ms.mh+' '+ // right + 'Z' // close + var pathTop = this.paper.path(strTop); + + // // outline of left + var strLeft= + 'M'+ms.mw +' '+ms.th+' '+ // middle + 'L'+ms.bw +' '+ms.uq+' '+ // left top + 'L'+ms.bw +' '+ms.lq+' '+ // left bottom + 'L'+ms.mw +' '+ms.sh+' '+ // middle bottom + 'Z' + var pathLeft = this.paper.path(strLeft); + // + // right + var strRight= + 'M'+ms.mw +' '+ms.th+' '+ // middle + 'L'+ms.mw +' '+ms.sh +' '+ // middle bottom + 'L'+ms.tw +' '+ms.lq+' '+ // right bottom + 'L'+ms.tw +' '+ms.uq+' '+ // right top + 'Z' // close + var pathRight = this.paper.path(strRight); + + // join into set + var pathGroup = this.paper.group(); + pathGroup.append(pathTop); + pathGroup.append(pathLeft); + pathGroup.append(pathRight); + + // set attrs from options + // ref http://raphaeljs.com/reference.html#Element.attr + var blackList = ['url','target','src','title'] + for (var a in this.options.stroke){ + if (this.options.stroke.hasOwnProperty(a) && blackList.indexOf(a)<0){ + pathGroup.attr(a,this.options.stroke[a]); + } + } + this.outline=pathGroup; +} + + +/* draw outline get line color from option.strokeColor, and width from options.stroke-width */ +SvgCube.prototype.drawShading = function(lw){ + lw=lw||this.options.stroke["stroke-width"]; + var ms = this.measurements(0); + var pathGroup = this.paper.g(); + + var strTop= + 'M'+ms.mw +' '+ms.th +' '+ // Move to bottom + 'L'+ms.bw +' '+ms.mh+' '+ // left + 'L'+ms.mw +' '+ms.bh+ ' '+ // top + 'L'+ms.tw +' '+ms.mh+' '+ // right + 'Z' // close + var pathTop = this.paper.path(strTop); + pathGroup.append(pathTop); + + // outline of left + var strLeft= + 'M'+ms.mw +' '+ms.th+' '+ // middle + 'L'+ms.bw +' '+ms.uq+' '+ // left top + 'L'+ms.bw +' '+ms.lq+' '+ // left bottom + 'L'+ms.mw +' '+ms.sh+' '+ // middle bottom + 'Z' + var pathLeft = this.paper.path(strLeft); + pathGroup.append(pathLeft); + + // last line from middle down + var strRight= + 'M'+ms.mw +' '+ms.th+' '+ // middle + 'L'+ms.mw +' '+ms.sh +' '+ // middle bottom + 'L'+ms.tw +' '+ms.lq+' '+ // right bottom + 'L'+ms.tw +' '+ms.uq+' '+ // right top + 'Z' // close + var pathRight = this.paper.path(strRight); + pathGroup.append(pathRight); + + + // style the set + pathGroup.attr({ + 'stroke': 'none', + 'fill': 'black', + 'stroke-width': 0, + 'stroke-opacity': 0, + 'stroke-linecap': 'round', + 'stroke-linejoin': 'round' + }); + // shade each side, 0 is no shading, 1 is black + pathTop.attr({'fill-opacity': this.options.topShad}); + pathLeft.attr({'fill-opacity': this.options.leftShad}); + pathRight.attr({'fill-opacity': this.options.rightShad}); + this.shading=pathGroup; + +} + +/*clip the cube using an elipse to give rounded corners */ +SvgCube.prototype.clipCircle = function(amount){ + var cp = document.createElementNS("http://www.w3.org/2000/svg","clipPath") + cp.id="cp"; + var rxc=51+4*(1-this.f)*(1-this.f); + var ryc=50-2/Math.sqrt(1-this.f); + cp.innerHTML = '' + this.paper.node.getElementsByTagName("defs")[0].appendChild(cp); + this.paper.node.setAttribute("clip-path","url(#cp)"); +} + + +/* returns svg string */ +SvgCube.prototype.toSVG = function(){ + var svg3 = this.paper.toString(); + //var svg = this.paper.node.outerHTML; + //var svg2 = xmlserializer.serializeToString(this.paper.node); + if (this.paper.node.attributes.getNamedItem("clip-path")){ + // patch svg export to add clip + // HACK I have to add these manually to the export sadly as raphael.export doesn't handle them and also misses some recent change to canvas + svg3=svg3.replace(" 5) { + console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat] [zoom]'); + console.log(' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"'); + console.log(' image (png/jpg output) examples: "1920px" entire page, window width 1920px'); + console.log(' "800px*600px" window, clipped to 800x600'); + phantom.exit(1); +} else { + address = system.args[1]; + output = system.args[2]; + page.viewportSize = { width: 600, height: 600 }; + if (system.args.length > 3 && system.args[2].substr(-4) === ".pdf") { + size = system.args[3].split('*'); + page.paperSize = size.length === 2 ? { width: size[0], height: size[1], margin: '0px' } + : { format: system.args[3], orientation: 'portrait', margin: '1cm' }; + } else if (system.args.length > 3 && system.args[3].substr(-2) === "px") { + size = system.args[3].split('*'); + if (size.length === 2) { + pageWidth = parseInt(size[0], 10); + pageHeight = parseInt(size[1], 10); + page.viewportSize = { width: pageWidth, height: pageHeight }; + page.clipRect = { top: 0, left: 0, width: pageWidth, height: pageHeight }; + } else { + console.log("size:", system.args[3]); + pageWidth = parseInt(system.args[3], 10); + pageHeight = parseInt(pageWidth * 3/4, 10); // it's as good an assumption as any + console.log ("pageHeight:",pageHeight); + page.viewportSize = { width: pageWidth, height: pageHeight }; + } + } + if (system.args.length > 4) { + page.zoomFactor = system.args[4]; + } + page.open(address, function (status) { + if (status !== 'success') { + console.log('Unable to load the address!'); + phantom.exit(1); + } else { + window.setTimeout(function () { + page.render(output); + phantom.exit(); + }, 200); + } + }); +} diff --git a/right.svg b/right.svg new file mode 100644 index 0000000..b87a0ff --- /dev/null +++ b/right.svg @@ -0,0 +1,2439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/svg-stylesheet.css b/svg-stylesheet.css new file mode 100644 index 0000000..3181dfd --- /dev/null +++ b/svg-stylesheet.css @@ -0,0 +1,43 @@ + .cube, .cube .face, .cube .face * { + height: 170px; + width: 170px; + } + .cube { + position: relative; + -webkit-transform: translate(11em,11em) + transform: translate(11em,11em) + } + + .cube * { + transform-origin: 0% 100%; + } + + .cube2 .top { + position: relative; + -webkit-transform: rotateX(45deg) rotateZ(-45deg) rotateX(0deg); + -webkit-transform-style: preserve-3d; + -webkit-transition: .25s; + transform: rotateX(45deg) rotateZ(-45deg) rotateX(0deg); + transform-style: preserve-3d; + transition: .25s; + + } + .cube2 .left { + -webkit-transform: rotateX(45deg) rotateZ(-45deg) rotateX(90deg); + -webkit-transform-style: preserve-3d; + -webkit-transition: .25s; + transform: rotateX(45deg) rotateZ(-45deg) rotateX(90deg); + transform-style: preserve-3d; + transition: .25s; + position: absolute; + + } + .cube2 .right { + -webkit-transform: rotateX(45deg) rotateZ(-45deg) rotateY(90deg); + -webkit-transform-style: preserve-3d; + -webkit-transition: .25s; + transform: rotateX(45deg) rotateZ(-45deg) rotateY(90deg); + transform-style: preserve-3d; + transition: .25s; + position: absolute; + } diff --git a/test.html b/test.html new file mode 100644 index 0000000..6631cba --- /dev/null +++ b/test.html @@ -0,0 +1,56 @@ + + https://en.wikipedia.org/wiki/Isometric_projection + + + + + + + + + + + diff --git a/test2.html b/test2.html new file mode 100644 index 0000000..8895906 --- /dev/null +++ b/test2.html @@ -0,0 +1,97 @@ + + + + Snap.js isometric SVG + + + +
+ + + + + + + + + + + + + diff --git a/top.svg b/top.svg new file mode 100644 index 0000000..e1b67bc --- /dev/null +++ b/top.svg @@ -0,0 +1,2384 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/webdriver_rasterize.js b/webdriver_rasterize.js new file mode 100644 index 0000000..3c6c832 --- /dev/null +++ b/webdriver_rasterize.js @@ -0,0 +1,52 @@ +var webdriverio = require('webdriverio'); + +var path = require('path'); +var fs = require('fs'); +var system = require('system') +var globby = require('globby'); + +var options = { + desiredCapabilities: { + browserName: 'chrome' + } +}; + +var config = { + debug: true +} + +var input = process.argv[2]; +console.log('input:',input); + + +globby(input).then(inputs => { + console.log('glob(',input,') =>', inputs); + for (var i=0; i',outfile); + webdriverio + .remote(options) + .init() + .url(url) + .getTitle().then(function(title) { + console.log('Title is: ' + title); + }) + .saveScreenshot( + [outfile], + function(err, screenshot, response) { + if (config.debug){ + console.log({file,err,screenshot,response}); + } else if (err){ + 'saveScreenshot',console.log(err); + } + } + ) + .end(); + } +}, this) +