diff options
author | Ulrich-Matthias Schäfer <ulima.ums@googlemail.com> | 2018-12-01 15:29:12 +0100 |
---|---|---|
committer | Ulrich-Matthias Schäfer <ulima.ums@googlemail.com> | 2018-12-01 15:29:12 +0100 |
commit | a463c31c9453e9e12242886297362ca7e5f7875d (patch) | |
tree | 2c55c88512e1b142ec4a60c9fb568656feb8c25e /src/types | |
parent | d549b00dc9d593e121236c64ab7c8f986a0800ac (diff) | |
parent | b5fc96a3637756e1c432464c18907f010311766e (diff) | |
download | svg.js-a463c31c9453e9e12242886297362ca7e5f7875d.tar.gz svg.js-a463c31c9453e9e12242886297362ca7e5f7875d.zip |
Merge branch '790-color-spaces' into 791-random-colors
Diffstat (limited to 'src/types')
-rw-r--r-- | src/types/Box.js | 26 | ||||
-rw-r--r-- | src/types/Color.js | 75 | ||||
-rw-r--r-- | src/types/Morphable.js | 246 |
3 files changed, 56 insertions, 291 deletions
diff --git a/src/types/Box.js b/src/types/Box.js index c90c7e0..d2ddcdd 100644 --- a/src/types/Box.js +++ b/src/types/Box.js @@ -104,7 +104,7 @@ export default class Box { } } -function getBox (cb) { +function getBox (cb, retry) { let box try { @@ -114,23 +114,29 @@ function getBox (cb) { throw new Error('Element not in the dom') } } catch (e) { - try { - let clone = this.clone().addTo(parser().svg).show() - box = cb(clone.node) - clone.remove() - } catch (e) { - throw new Error('Getting a bounding box of element "' + this.node.nodeName + '" is not possible') - } + box = retry(this) } + return box } export function bbox () { - return new Box(getBox.call(this, (node) => node.getBBox())) + return new Box(getBox.call(this, (node) => node.getBBox(), (el) => { + try { + let clone = el.clone().addTo(parser().svg).show() + let box = clone.node.getBBox() + clone.remove() + return box + } catch (e) { + throw new Error('Getting bbox of element "' + el.node.nodeName + '" is not possible') + } + })) } export function rbox (el) { - let box = new Box(getBox.call(this, (node) => node.getBoundingClientRect())) + let box = new Box(getBox.call(this, (node) => node.getBoundingClientRect(), (el) => { + throw new Error('Getting rbox of element "' + el.node.nodeName + '" is not possible') + })) if (el) return box.transform(el.screenCTM().inverse()) return box.addOffset() } diff --git a/src/types/Color.js b/src/types/Color.js index 1f23592..a1329aa 100644 --- a/src/types/Color.js +++ b/src/types/Color.js @@ -19,22 +19,24 @@ function componentHex (component) { } function is (object, space) { - for (const key of space) { - if (object[key] == null) { + for (let i = space.length; i--;) { + if (object[space[i]] == null) { return false } } return true } -function getParameters (a) { +function getParameters (a, b) { const params = is(a, 'rgb') ? { _a: a.r, _b: a.g, _c: a.b, space: 'rgb' } - : is(a, 'xyz') ? { _a: a.x, _b: a.y, _c: a.z, space: 'xyz' } - : is(a, 'hsl') ? { _a: a.h, _b: a.s, _c: a.l, space: 'hsl' } - : is(a, 'lab') ? { _a: a.l, _b: a.a, _c: a.b, space: 'lab' } - : is(a, 'lch') ? { _a: a.l, _b: a.c, _c: a.h, space: 'lch' } + : is(a, 'xyz') ? { _a: a.x, _b: a.y, _c: a.z, _d: 0, space: 'xyz' } + : is(a, 'hsl') ? { _a: a.h, _b: a.s, _c: a.l, _d: 0, space: 'hsl' } + : is(a, 'lab') ? { _a: a.l, _b: a.a, _c: a.b, _d: 0, space: 'lab' } + : is(a, 'lch') ? { _a: a.l, _b: a.c, _c: a.h, _d: 0, space: 'lch' } : is(a, 'cmyk') ? { _a: a.c, _b: a.m, _c: a.y, _d: a.k, space: 'cmyk' } : { _a: 0, _b: 0, _c: 0, space: 'rgb' } + + params.space = b || params.space return params } @@ -61,31 +63,38 @@ export default class Color { } init (a = 0, b = 0, c = 0, d = 0, space = 'rgb') { - // If the user gave us an array, make the color from it + // Reset all values in case the init function is rerun with new color space + if (this.space) { + for (let component in this.space) { + delete this[this.space[component]] + } + } + if (typeof a === 'number') { // Allow for the case that we don't need d... space = typeof d === 'string' ? d : space - d = typeof d === 'string' ? undefined : d + d = typeof d === 'string' ? 0 : d // Assign the values straight to the color Object.assign(this, { _a: a, _b: b, _c: c, _d: d, space }) + // If the user gave us an array, make the color from it } else if (a instanceof Array) { - this.space = b || 'rgb' - Object.assign(this, { _a: a[0], _b: a[1], _c: a[2], _d: a[3] }) + this.space = b || (typeof a[3] === 'string' ? a[3] : a[4]) || 'rgb' + Object.assign(this, { _a: a[0], _b: a[1], _c: a[2], _d: a[3] || 0 }) } else if (a instanceof Object) { // Set the object up and assign its values directly - const values = getParameters(a) + const values = getParameters(a, b) Object.assign(this, values) } else if (typeof a === 'string') { if (isRgb.test(a)) { const noWhitespace = a.replace(whitespace, '') const [ _a, _b, _c ] = rgb.exec(noWhitespace) .slice(1, 4).map(v => parseInt(v)) - Object.assign(this, { _a, _b, _c, space: 'rgb' }) + Object.assign(this, { _a, _b, _c, _d: 0, space: 'rgb' }) } else if (isHex.test(a)) { const hexParse = v => parseInt(v, 16) const [ , _a, _b, _c ] = hex.exec(sixDigitHex(a)).map(hexParse) - Object.assign(this, { _a, _b, _c, space: 'rgb' }) + Object.assign(this, { _a, _b, _c, _d: 0, space: 'rgb' }) } else throw Error(`Unsupported string format, can't construct Color`) } @@ -101,20 +110,6 @@ export default class Color { Object.assign(this, components) } - opacity (opacity = 1) { - this.opacity = opacity - } - - /* - - */ - - brightness () { - const { _a: r, _b: g, _c: b } = this.rgb() - const value = (r / 255 * 0.30) + (g / 255 * 0.59) + (b / 255 * 0.11) - return value - } - /* Conversion Methods */ @@ -174,6 +169,7 @@ export default class Color { // If we are grey, then just make the color directly if (s === 0) { + l *= 255 let color = new Color(l, l, l) return color } @@ -304,6 +300,12 @@ export default class Color { // Get the cmyk values in an unbounded format const k = Math.min(1 - r, 1 - g, 1 - b) + + if (k === 1) { + // Catch the black case + return new Color(0, 0, 0, 1, 'cmyk') + } + const c = (1 - r - k) / (1 - k) const m = (1 - g - k) / (1 - k) const y = (1 - b - k) / (1 - k) @@ -317,21 +319,24 @@ export default class Color { Input and Output methods */ - hex () { + _clamped () { let { _a, _b, _c } = this.rgb() - let [ r, g, b ] = [ _a, _b, _c ].map(componentHex) + let { max, min, round } = Math + let format = v => max(0, min(round(v), 255)) + return [ _a, _b, _c ].map(format) + } + + toHex () { + let [ r, g, b ] = this._clamped().map(componentHex) return `#${r}${g}${b}` } toString () { - return this.hex() + return this.toHex() } toRgb () { - let { r, g, b } = this.rgb() - let { max, min, round } = Math - let format = v => max(0, min(round(v), 255)) - let [ rV, gV, bV ] = [ r, g, b ].map(format) + let [ rV, gV, bV ] = this._clamped() let string = `rgb(${rV},${gV},${bV})` return string } diff --git a/src/types/Morphable.js b/src/types/Morphable.js deleted file mode 100644 index 240215b..0000000 --- a/src/types/Morphable.js +++ /dev/null @@ -1,246 +0,0 @@ -import { Ease } from '../animation/Controller.js' -import { - delimiter, - numberAndUnit, - pathLetters -} from '../modules/core/regex.js' -import { extend } from '../utils/adopter.js' -import Color from './Color.js' -import PathArray from './PathArray.js' -import SVGArray from './SVGArray.js' -import SVGNumber from './SVGNumber.js' - -export default class Morphable { - constructor (stepper) { - this._stepper = stepper || new Ease('-') - - this._from = null - this._to = null - this._type = null - this._context = null - this._morphObj = null - } - - from (val) { - if (val == null) { - return this._from - } - - this._from = this._set(val) - return this - } - - to (val) { - if (val == null) { - return this._to - } - - this._to = this._set(val) - return this - } - - type (type) { - // getter - if (type == null) { - return this._type - } - - // setter - this._type = type - return this - } - - _set (value) { - if (!this._type) { - var type = typeof value - - if (type === 'number') { - this.type(SVGNumber) - } else if (type === 'string') { - if (Color.isColor(value)) { - this.type(Color) - } else if (delimiter.test(value)) { - this.type(pathLetters.test(value) - ? PathArray - : SVGArray - ) - } else if (numberAndUnit.test(value)) { - this.type(SVGNumber) - } else { - this.type(NonMorphable) - } - } else if (morphableTypes.indexOf(value.constructor) > -1) { - this.type(value.constructor) - } else if (Array.isArray(value)) { - this.type(SVGArray) - } else if (type === 'object') { - this.type(ObjectBag) - } else { - this.type(NonMorphable) - } - } - - var result = (new this._type(value)).toArray() - this._morphObj = this._morphObj || new this._type() - this._context = this._context - || Array.apply(null, Array(result.length)).map(Object) - return result - } - - stepper (stepper) { - if (stepper == null) return this._stepper - this._stepper = stepper - return this - } - - done () { - var complete = this._context - .map(this._stepper.done) - .reduce(function (last, curr) { - return last && curr - }, true) - return complete - } - - at (pos) { - var _this = this - - return this._morphObj.fromArray( - this._from.map(function (i, index) { - return _this._stepper.step(i, _this._to[index], pos, _this._context[index], _this._context) - }) - ) - } -} - -export class NonMorphable { - constructor (...args) { - this.init(...args) - } - - init (val) { - val = Array.isArray(val) ? val[0] : val - this.value = val - return this - } - - valueOf () { - return this.value - } - - toArray () { - return [ this.value ] - } -} - -export class TransformBag { - constructor (...args) { - this.init(...args) - } - - init (obj) { - if (Array.isArray(obj)) { - obj = { - scaleX: obj[0], - scaleY: obj[1], - shear: obj[2], - rotate: obj[3], - translateX: obj[4], - translateY: obj[5], - originX: obj[6], - originY: obj[7] - } - } - - Object.assign(this, TransformBag.defaults, obj) - return this - } - - toArray () { - var v = this - - return [ - v.scaleX, - v.scaleY, - v.shear, - v.rotate, - v.translateX, - v.translateY, - v.originX, - v.originY - ] - } -} - -TransformBag.defaults = { - scaleX: 1, - scaleY: 1, - shear: 0, - rotate: 0, - translateX: 0, - translateY: 0, - originX: 0, - originY: 0 -} - -export class ObjectBag { - constructor (...args) { - this.init(...args) - } - - init (objOrArr) { - this.values = [] - - if (Array.isArray(objOrArr)) { - this.values = objOrArr - return - } - - var entries = Object.entries(objOrArr || {}).sort((a, b) => { - return a[0] - b[0] - }) - - this.values = entries.reduce((last, curr) => last.concat(curr), []) - return this - } - - valueOf () { - var obj = {} - var arr = this.values - - for (var i = 0, len = arr.length; i < len; i += 2) { - obj[arr[i]] = arr[i + 1] - } - - return obj - } - - toArray () { - return this.values - } -} - -const morphableTypes = [ - NonMorphable, - TransformBag, - ObjectBag -] - -export function registerMorphableType (type = []) { - morphableTypes.push(...[].concat(type)) -} - -export function makeMorphable () { - extend(morphableTypes, { - to (val) { - return new Morphable() - .type(this.constructor) - .from(this.valueOf()) - .to(val) - }, - fromArray (arr) { - this.init(arr) - return this - } - }) -} |