react-native-painter
Version:
Custom Painter Android WEB IOS
394 lines (317 loc) • 15.4 kB
JavaScript
import React, { useRef } from 'react'
import Attributes from './Constants'
const getPosition = (arr,index,length)=>{
if(arr !== undefined){
return `${arr[index] * 100}%`
}
if(length > 0){
let l = length - 1
let sum = 1 / l
return index == l ? "100%" : `${(index*sum) * 100}%`
}
return "0%"
}
const RadialGradientWeb = React.forwardRef((props,ref)=>{
const myRef = ref ? ref : useRef()
const {
x,
y,
w,
h,
cx,
cy,
rx,
ry,
positions,
colors,
painterKey,
viewBox,
align,
aspect,
isChildMask,
fill,
fillRule,
fillOpacity,
stroke,
strokeOpacity,
strokeWidth,
strokeStart,
strokeEnd,
dashArray,
dashClipValue,
strokeCap,
strokeJoin,
strokeMiter,
shadow,
shadowRadius,
shadowOffset,
shadowOffsetX,
shadowOffsetY,
shadowPercentageValue,
shadowRect,
mask,
opacity,
translateZ,
transX,
transY,
transPercentageValue,
rot,
rotO,
rotOx,
rotOy,
rotPercentageValue,
sc,
scX,
scY,
scO,
scOx,
scOy,
scPercentageValue,
style,
...rest
} = props
//MARK: Props
const lx = x === undefined ? 0 : x
const ly = y === undefined ? 0 : y
const lw = w === undefined ? 0 : w
const lh = h === undefined ? 0 : h
const centerX = cx === undefined ? 0.5 : cx
const centerY = cy === undefined ? 0.5 : cy
const radiusX = rx === undefined ? 0.5 : rx
const radiusY = ry === undefined ? 0.5 : ry
const colorsArr = colors === undefined ? ['white','black'] : colors
//MARK : Paintable
const isMasking = isChildMask === undefined ? false : isChildMask
const mk = mask === undefined ? "" : mask
const op = opacity === undefined ? "" : `${opacity}`
const dx = transX === undefined ? 0 : transX
const dy = transY === undefined ? 0 : transY
const scaleX = sc === undefined ? ( scX === undefined ? 1 : scX) : sc
const scaleY = sc === undefined ? (scY === undefined ? 1 : scY) : sc
const scaleOX = scO === undefined ? ( scOx === undefined ? 0 : scOx) : scO
const scaleOY = scO === undefined ? (scOy === undefined ? 0 : scOy) : scO
const rotation = rot === undefined ? 0 : rot
const rotationOX = rotO === undefined ? ( rotOx === undefined ? 0 : rotOx) : rotO
const rotationOY = rotO === undefined ? (rotOy === undefined ? 0 : rotOy) : rotO
const transform = `rotate(${rotation} ${rotationOX} ${rotationOY}) translate(${scaleOX} ${scaleOY}) scale(${scaleX} ${scaleY}) translate(${-scaleOX} ${-scaleOY}) translate(${dx} ${dy})`
const userKey = painterKey === undefined ? "" : painterKey
const keyElemet = Attributes.elements.prefix
const keyGradient = `${keyElemet}${Attributes.elements.gradient}${userKey}`
return(
<g ref={myRef} opacity={op} mask={`url(#${mk})`} transform={transform}
curtransform={`${rotation} ${rotationOX} ${rotationOY} ${scaleX} ${scaleY} ${scaleOX} ${scaleOY} ${dx} ${dy}`}
curcolors={`${colorsArr.join(';-;')}`} curpositions={`${positions === undefined ? "" : positions.join(' ')}`}
curradiusx={radiusX} curradiusy={radiusY}
>
<svg style={{width:'100%',height:'100%',overflow:'visible'}} viewBox={viewBox}
preserveAspectRatio={`${align} ${aspect}`}>
<defs>
<radialGradient id={keyGradient}
gradientUnits="objectBoundingBox"
gradientTransform={`translate(0.5 0.5) scale(1,${radiusY/radiusX}) translate(-0.5 -0.5)`}
cx={centerX} cy={centerY} r={radiusX} >
{colorsArr.map((color,index)=>{
return(
<stop key={index} offset={getPosition(positions,index,colorsArr.length)} stopColor={color} />
)
})}
</radialGradient>
</defs>
<rect
id={`${keyElemet}${Attributes.elements.fill}${userKey}`}
x={lx} y={ly} width={lw} height={lh} fill={`url(#${keyGradient})`}/>
</svg>
</g>
)
})
class RadialGradient extends React.PureComponent{
constructor(props){
super(props)
this.currentProps = Object.assign({},props)
this.keyElemet = Attributes.elements.prefix
this.myRef = React.createRef()
this.setNativeProps = this.setNativeProps.bind(this)
this.updateProp = this.updateProp.bind(this)
this.handleProps = this.handleProps.bind(this)
this.handleCommonProps = this.handleCommonProps.bind(this)
this.updateAttribute = this.updateAttribute.bind(this)
this.getAttribute = this.getAttribute.bind(this)
this.getElement = this.getElement.bind(this)
}
//direct manipulation, experimental
setNativeProps(object){
if(this.myRef.current && this.props.painterKey){
let keys = Object.keys(object)
for(var i = 0; i < keys.length;i++){
let k = keys[i]
let value = object[k]
this.updateProp(k,value)
}
let isStyle = object.hasOwnProperty('style')
if(isStyle){
let keysStyle = Object.keys(object.style)
for(var i = 0; i < keysStyle.length;i++){
let k = keysStyle[i]
let value = object.style[k]
this.updateProp(k,value)
}
}
}
}
updateProp(k,value){
let isProp = this.handleProps(k,value)
if(!isProp){
this.handleCommonProps(k,value)
}
}
handleProps(k,value){
switch(k){
case "x":
case "y":
case "w":
case "h":
let elfill = this.getElement(Attributes.elements.fill)
this.updateAttribute(Attributes[k],value,elfill)
return true
case "cx":
case "cy":
this.updateAttribute(Attributes[k],value,this.getElement(Attributes.elements.gradient))
return true
case "rx":
this.updateAttribute(Attributes.r,value,this.getElement(Attributes.elements.gradient))
let curRy = parseFloat(this.getAttribute(Attributes.curRadiusY,this.myRef.current))
this.updateAttribute(Attributes.gradientTransform
,`translate(0.5 0.5) scale(1,${curRy/value}) translate(-0.5 -0.5)`,
this.getElement(Attributes.elements.gradient))
this.updateAttribute(Attributes.curRadiusX,value,this.myRef.current)
return true
case "ry":
let curRx = parseFloat(this.getAttribute(Attributes.curRadiusX,this.myRef.current))
this.updateAttribute(Attributes.gradientTransform
,`translate(0.5 0.5) scale(1,${value/curRx}) translate(-0.5 -0.5)`,
this.getElement(Attributes.elements.gradient))
this.updateAttribute(Attributes.curRadiusY,value,this.myRef.current)
return true
case "colors":
let gra = this.getElement(Attributes.elements.gradient)
gra.innerHTML = ""
if(value.length > 0){
let curPo = this.getAttribute(Attributes.curPositions,this.myRef.current)
let pos = curPo.length >= 1 ? curPo.split(' ') : undefined
let html = ""
for(var i = 0; i < value.length ; i++){
let c = value[i]
html += `<stop offset="${getPosition(pos,i,value.length)}" stop-color="${c}" /> \n`
}
gra.innerHTML = html
this.updateAttribute(Attributes.curColors,value.join(';-;'),this.myRef.current)
}
return true
case "positions":
let elG = this.getElement(Attributes.elements.gradient)
let curColors = this.getAttribute(Attributes.curColors,this.myRef.current)
let cols = curColors.length >= 1 ? curColors.split(';-;') : []
elG.innerHTML = ""
if(cols.length > 0){
let html = ""
for(var i = 0; i < cols.length ; i++){
let c = cols[i]
html += `<stop offset="${getPosition(value,i,cols.length)}" stop-color="${c}" /> \n`
}
elG.innerHTML = html
this.updateAttribute(Attributes.curPositions,value.join(' '),this.myRef.current)
}
return true
}
return false
}
handleCommonProps(k,value){
if(k.includes('fill')){
}else if(k.includes('stroke')){
}else if(k.includes('shadow')){
}else if(k === 'opacity'){
this.updateAttribute(Attributes[k],value,this.myRef.current)
}else if(k === 'mask'){
this.updateAttribute(Attributes[k],`url(#${value})`,this.myRef.current)
}else if(k === 'dashArray'){
}else if(k === 'dashClipValue'){
}//transform
else{
var container = this.myRef.current
let t = this.getAttribute(Attributes.curTransform,container).split(' ')
var valueT = ""
var currT = ""
switch(k){
case "transX":
valueT = `rotate(${t[0]} ${t[1]} ${t[2]}) translate(${t[5]} ${t[6]}) scale(${t[3]} ${t[4]}) translate(${-t[5]} ${-t[6]}) translate(${value} ${t[8]})`
currT = `${t[0]} ${t[1]} ${t[2]} ${t[3]} ${t[4]} ${t[5]} ${t[6]} ${value} ${t[8]}`
break;
case "transY":
valueT = `rotate(${t[0]} ${t[1]} ${t[2]}) translate(${t[5]} ${t[6]}) scale(${t[3]} ${t[4]}) translate(${-t[5]} ${-t[6]}) translate(${t[7]} ${value})`
currT = `${t[0]} ${t[1]} ${t[2]} ${t[3]} ${t[4]} ${t[5]} ${t[6]} ${t[7]} ${value}`
break;
case "rot":
valueT = `rotate(${value} ${t[1]} ${t[2]}) translate(${t[5]} ${t[6]}) scale(${t[3]} ${t[4]}) translate(${-t[5]} ${-t[6]}) translate(${t[7]} ${t[8]})`
currT = `${value} ${t[1]} ${t[2]} ${t[3]} ${t[4]} ${t[5]} ${t[6]} ${t[7]} ${t[8]}`
break;
case "rotO":
valueT = `rotate(${t[0]} ${value} ${value}) translate(${t[5]} ${t[6]}) scale(${t[3]} ${t[4]}) translate(${-t[5]} ${-t[6]}) translate(${t[7]} ${t[8]})`
currT = `${t[0]} ${value} ${value} ${t[3]} ${t[4]} ${t[5]} ${t[6]} ${t[7]} ${t[8]}`
break;
case "rotOx":
valueT = `rotate(${t[0]} ${value} ${t[2]}) translate(${t[5]} ${t[6]}) scale(${t[3]} ${t[4]}) translate(${-t[5]} ${-t[6]}) translate(${t[7]} ${t[8]})`
currT = `${t[0]} ${value} ${t[2]} ${t[3]} ${t[4]} ${t[5]} ${t[6]} ${t[7]} ${t[8]}`
break;
case "rotOy":
valueT = `rotate(${t[0]} ${t[1]} ${value}) translate(${t[5]} ${t[6]}) scale(${t[3]} ${t[4]}) translate(${-t[5]} ${-t[6]}) translate(${t[7]} ${t[8]})`
currT = `${t[0]} ${t[1]} ${value} ${t[3]} ${t[4]} ${t[5]} ${t[6]} ${t[7]} ${t[8]}`
break;
case "sc":
valueT = `rotate(${t[0]} ${t[1]} ${t[2]}) translate(${t[5]} ${t[6]}) scale(${value} ${value}) translate(${-t[5]} ${-t[6]}) translate(${t[7]} ${t[8]})`
currT = `${t[0]} ${t[1]} ${t[2]} ${value} ${value} ${t[5]} ${t[6]} ${t[7]} ${t[8]}`
break;
case "scX":
valueT = `rotate(${t[0]} ${t[1]} ${t[2]}) translate(${t[5]} ${t[6]}) scale(${value} ${t[4]}) translate(${-t[5]} ${-t[6]}) translate(${t[7]} ${t[8]})`
currT = `${t[0]} ${t[1]} ${t[2]} ${value} ${t[4]} ${t[5]} ${t[6]} ${t[7]} ${t[8]}`
break;
case "scY":
valueT = `rotate(${t[0]} ${t[1]} ${t[2]}) translate(${t[5]} ${t[6]}) scale(${t[3]} ${value}) translate(${-t[5]} ${-t[6]}) translate(${t[7]} ${t[8]})`
currT = `${t[0]} ${t[1]} ${t[2]} ${t[3]} ${value} ${t[5]} ${t[6]} ${t[7]} ${t[8]}`
break;
case "scO":
valueT = `rotate(${t[0]} ${t[1]} ${t[2]}) translate(${value} ${value}) scale(${t[3]} ${t[4]}) translate(${-value} ${-value}) translate(${t[7]} ${t[8]})`
currT = `${t[0]} ${t[1]} ${t[2]} ${t[3]} ${t[4]} ${value} ${value} ${t[7]} ${t[8]}`
break;
case "scOx":
valueT = `rotate(${t[0]} ${t[1]} ${t[2]}) translate(${value} ${t[6]}) scale(${t[3]} ${t[4]}) translate(${-value} ${-t[6]}) translate(${t[7]} ${t[8]})`
currT = `${t[0]} ${t[1]} ${t[2]} ${t[3]} ${t[4]} ${value} ${t[6]} ${t[7]} ${t[8]}`
break;
case "scOy":
valueT = `rotate(${t[0]} ${t[1]} ${t[2]}) translate(${t[5]} ${value}) scale(${t[3]} ${t[4]}) translate(${-t[5]} ${-value}) translate(${t[7]} ${t[8]})`
currT = `${t[0]} ${t[1]} ${t[2]} ${t[3]} ${t[4]} ${t[5]} ${value} ${t[7]} ${t[8]}`
break;
}
if(currT.length > 0 && valueT.length > 0 ){
this.updateAttribute(Attributes.transform,valueT,container)
this.updateAttribute(Attributes.curTransform,currT,container)
}
}
}
getElement(id){
return this.myRef.current.querySelector(`#${this.keyElemet}${id}${this.props.painterKey}`)
}
updateAttribute(k,value,element){
if(element) element.setAttribute(k,value)
}
getAttribute(k,element){
if(element) {
let v = element.getAttribute(k)
return v ? v : ""
}
return ""
}
render(){
return <RadialGradientWeb ref={this.myRef} {...this.props} />
}
}
export default RadialGradient