Skip to content

Instantly share code, notes, and snippets.

@sgss
Created January 14, 2012 13:12
Show Gist options
  • Save sgss/1611380 to your computer and use it in GitHub Desktop.
Save sgss/1611380 to your computer and use it in GitHub Desktop.
Length representation class
class Length
self = @
@_pattern : /^\s*([+\-]?\s*[\d.]+(?:e[+\-]\d+)?)\s*([^\s]+)?\s*$/
@_units:
pixel : 'pixel'
millimeter : 'millimeter'
centimeter : 'centimeter'
inch : 'inch'
point : 'point'
pica : 'pica'
@_notations:
'px' : 'pixel'
'mm' : 'millimeter'
'cm' : 'centimeter'
'in' : 'inch'
'pt' : 'point'
'pc' : 'pica'
@_conversions:
pixel:
pixel : 1
millimeter : 25.4 / 96
centimeter : 2.54 / 96
inch : 1 / 96
point : 72 / 96
pica : 6 / 96
millimeter:
pixel : 96 / 25.4
millimeter : 1
centimeter : 0.1
inch : 1 / 25.4
point : 72 / 25.4
pica : 6 / 25.4
centimeter:
pixel : 96 / 2.54
millimeter : 10
centimeter : 1
inch : 1 / 2.54
point : 72 / 2.54
pica : 6 / 2.54
inch:
pixel : 96
millimeter : 25.4
centimeter : 2.54
inch : 1
point : 72
pica : 6
point:
pixel : 96 / 72
millimeter : 25.4 / 72
centimeter : 2.54 / 72
inch : 1 / 72
point : 1
pica : 1 / 12
pica:
pixel : 96 / 6
millimeter : 25.4 / 6
centimeter : 2.54 / 6
inch : 1 / 6
point : 12
pica : 1
@_relativeUnits:
multiple : 'multiple'
em : 'em'
percent : 'percent'
permille : 'permille'
@_relativeNotations:
'x' : 'multiple'
'em' : 'em'
'%' : 'percent'
'‰' : 'permille'
@_relativeCoefficients:
multiple : 1
em : 1
percent : 0.01
permille : 0.001
# function : Pixel <value>
# returns : Length
#
@Pixel: (value) -> new self value, self._units.pixel
@Pixel.toString = -> self._units.pixel
# function : Millimeter <value>
# returns : Length
#
@Millimeter: (value) -> new self value, self._units.millimeter
@Millimeter.toString = -> self._units.millimeter
# function : Centimeter <value>
# returns : Length
#
@Centimeter: (value) -> new self value, self._units.centimeter
@Centimeter.toString = -> self._units.centimeter
# function : Inch <value>
# returns : Length
#
@Inch: (value) -> new self value, self._units.inch
@Inch.toString = -> self._units.inch
# function : Point <value>
# returns : Length
#
@Point: (value) -> new self value, self._units.point
@Point.toString = -> self._units.point
# function : Pica <value>
# returns : Length
#
@Pica: (value) -> new self value, self._units.pica
@Pica.toString = -> self._units.pica
# function : create [value], [unit], [primitive]
# returns : Length
#
@create: (value, unit, primitive) -> new self value, unit, primitive
# function : extract <notation>
# returns : Object
#
@extract: (notation) ->
if self._pattern.test notation
{ value: Number(RegExp.$1), unit: RegExp.$2 }
else
{ value: 0, unit: null }
# function : profileUnit unit
# returns : Object
#
@profileUnit: (unit) ->
unit = unit?.toString().toLowerCase()
if self._notations[unit]?
{ unit: self._notations[unit], relative: no, absolute: yes }
else if self._units[unit]?
{ unit: unit, relative: no, absolute: yes }
else if self._relativeNotations[unit]?
{ unit: self._relativeNotations[unit], relative: yes, absolute: no }
else if self._relativeUnits[unit]?
{ unit: unit, relative: yes, absolute: no }
else
{ unit: null, relative: no, absolute: no }
# function : relativate <value>, <length>, [unit]
# returns : mixed
#
@convertValueRelativeTo: (value, length, targetUnit) ->
length = new Length length
{ unit: targetUnit, relative: targetRelative, absolute: targetAbsolute } = self.profileUnit targetUnit
if value instanceof self
# absolute to relative
if targetRelative
value.valueOf(length.getUnit()) / length.valueOf() / self._relativeCoefficients[targetUnit]
# absolute to absolute
else if targetAbsolute
value[targetUnit]()
# default absolute
else
value
else
{ value, unit } = Length.extract value
{ unit, relative, absolute } = self.profileUnit unit
if relative
# relative to relative
if targetRelative
value * self._relativeCoefficients[unit] / self._relativeCoefficients[targetUnit]
# relative to absolute
else if targetAbsolute
new Length length.valueOf(targetUnit) * value * self._relativeCoefficients[unit], targetUnit
# default relative
else
new Length length.valueOf() * value * self._relativeCoefficients[unit], length.getUnit()
else if absolute
# absolute to relative
if targetRelative
new Length(value, unit).valueOf(length.getUnit()) / length.valueOf() / self._relativeCoefficients[targetUnit]
# absolute to absolute
else if targetAbsolute
new Length value, targetUnit, unit
# default absolute
else
new Length value, unit
#---------------------------------------------------------------------------
#
# Initialization
#
#---------------------------------------------------------------------------
# function : Length [value], [unit], [primitive]
#
constructor: (value, unit, primitive) ->
# Length <length>, [unit], primitive
if value instanceof self
if isString unit
unit = unit.toLowerCase()
if self._notations[unit]?
unit = self._notations[unit]
else unless self._units[unit]?
unit = value._unit
if isString primitive
primitive = primitive.toLowerCase()
if self._notations[primitive]?
primitive = self._notations[primitive]
else unless self._units[primitive]
primitive = value._primitive
@_value = value.valueOf primitive
@_unit = unit
@_primitive = primitive
else
if isString unit
unit = unit.toLowerCase()
if self._notations[unit]?
unit = self._notations[unit]
else unless self._units[unit]?
unit = self._units.pixel
if isString primitive
primitive = primitive.toLowerCase()
if self._notations[primitive]?
primitive = self._notations[primitive]
else unless self._units[primitive]?
primitive = unit
# Length [value], [unit = 'pixel'], [primitive]
if isNumber value
@_value = value
@_unit = unit
@_primitive = primitive
# Length <notation>
else if self._pattern.test value
found = RegExp.$2.toLowerCase()
if self._notations[found]
unit = self._notations[found]
else if self._units[found]
unit = found
@_value = Number(RegExp.$1)
@_unit = unit
@_primitive = unit
# Length
else
@_value = 0
@_unit = unit
@_primitive = primitive
#---------------------------------------------------------------------------
#
# Utility
#
#---------------------------------------------------------------------------
# method : valueOf [unit]
# returns : Number
#
valueOf: (unit) ->
if self._notations[unit]?
unit = self._notations[unit]
if not unit?
unit = @_unit
@_value * self._conversions[@_primitive][unit]
# method : toString
# returns : String
#
toString: -> @_value + ' ' + @_unit
# method : equals <other>
# returns : Boolean
#
equals: (other) ->
if other? and other.valueOf?
@valueOf(Length.Pixel) is other.valueOf(Length.Pixel)
else
@valueOf(@_primitive) is other
# method : clone
# returns : Length
#
clone: -> new self @_value, @_unit, @_primitive
#---------------------------------------------------------------------------
#
# Accessing Property
#
#---------------------------------------------------------------------------
# method : getValue
# returns : Number
#
getValue: -> @_value
# method : getUnit
# returns : String
#
getUnit: -> @_unit
# method : getPrimitive
# returns : String
#
getPrimitive: -> @_primitive
#---------------------------------------------------------------------------
#
# Converting Unit
#
#---------------------------------------------------------------------------
# method : pixel
# returns : Length
#
pixel: ->
if @_unit isnt self._units.pixel
new self @_value, self._units.pixel, @_primitive
else
@
# method : millimeter
# returns : Length
#
millimeter: ->
if @_unit isnt self._units.millimeter
new self @_value, self._units.millimeter, @_primitive
else
@
# method : centimeter
# returns : Length
#
centimeter: ->
if @_unit isnt self._units.centimeter
new self @_value, self._units.centimeter, @_primitive
else
@
# method : inch
# returns : Length
#
inch: ->
if @_unit isnt self._units.inch
new self @_value, self._units.inch, @_primitive
else
@
# method : point
# returns : Length
#
point: ->
if @_unit isnt self._units.point
new self @_value, self._units.point, @_primitive
else
@
# method : pica
# returns : Length
#
pica: ->
if @_unit isnt self._units.pica
new self @_value, self._units.pica, @_primitive
else
@
#---------------------------------------------------------------------------
#
# Manipulating Numeric Value
#
#---------------------------------------------------------------------------
# method : abs
# returns : Length
#
abs: -> new self @valueOf().abs(), @_primitive
# method : ceil [precision]
# returns : Length
#
ceil: (precision) -> new self @valueOf().ceil(precision), @_primitive
# method : floor [precision]
# returns : Length
#
floor: (precision) -> new self @valueOf().floor(precision), @_primitive
# method : round [precision]
# returns : Length
#
round: (precision) -> new self @valueOf().round(precision), @_primitive
# method : pow [p]
# returns : Length
#
pow: (p) -> new self @valueOf().pow(p), @_primitive
#-------------------------------------------------------------------------------
#
# Converting Length to Number
#
#-------------------------------------------------------------------------------
merge Number,
# function : Pixel <value>
# returns : Length
#
Pixel: (value) ->
if value instanceof Length
value.valueOf Length._units.pixel
else
new Length(value).valueOf Length._units.pixel
# function : Millimeter <value>
# returns : Length
#
Millimeter: (value) ->
if value instanceof Length
value.valueOf Length._units.millimeter
else
new Length(value).valueOf Length._units.millimeter
# function : Centimeter <value>
# returns : Length
#
Centimeter: (value) ->
if value instanceof Length
value.valueOf Length._units.centimeter
else
new Length(value).valueOf Length._units.centimeter
# function : Inch <value>
# returns : Length
#
Inch: (value) ->
if value instanceof Length
value.valueOf Length._units.inch
else
new Length(value).valueOf Length._units.inch
# function : Point <value>
# returns : Length
#
Point: (value) ->
if value instanceof Length
value.valueOf Length._units.point
else
new Length(value).valueOf Length._units.point
# function : Pica <value>
# returns : Length
#
Pica: (value) ->
if value instanceof Length
value.valueOf Length._units.millimeter
else
new Length(value).valueOf Length._units.pica
#-------------------------------------------------------------------------------
#
# Converting Number to Length
#
#-------------------------------------------------------------------------------
merge Number::,
# method : pixel
# returns : Length
#
pixel: -> new Length @, Length._units.pixel
# method : millimeter
# returns : Length
#
millimeter: -> new Length @, Length._units.millimeter
# method : centimeter
# returns : Length
#
centimeter: -> new Length @, Length._units.centimeter
# method : inch
# returns : Length
#
inch: -> new Length @, Length._units.inch
# method : point
# returns : Length
#
point: -> new Length @, Length._units.point
# method : pica
# returns : Length
#
pica: -> new Length @, Length._units.pica
#-------------------------------------------------------------------------------
#
# Converting String to Length
#
#-------------------------------------------------------------------------------
merge String::,
# method : toLength
# returns : Length
#
toLength: -> new Length @
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment