lucassaid / react-native-cool-speedometer

Cool speedometer for React Native
27 stars 20 forks source link

Speedometer throws exception with custom fonts #9

Closed EmilianoMorghen closed 2 years ago

EmilianoMorghen commented 2 years ago

Hello @lucassaid, first of thank you for your work. This component is really good.

In documentation you say: image

I've got a bunch of custom fonts already configured inside my app and I can use them elsewhere in the project but looks like when I try to feed them to the Speedometer it throws exception "Unrecognized font family 'roboto'". image

Maybe Speedometer wants the fonts to be configured in some other way. Could you provide and example of custom font being used? Or maybe you know what's the proper way to configure a font for Speedometer? (I've used a custom hook to load the fonts and in other components my fonts works just fine)

Thank you in advance for you time

lucassaid commented 2 years ago

Hey, I'm glad you like the library 😃

I reviewed the code and it's not doing anything special with that fontFamily property, it just get passed to a <Text> element.

The Text element used is from 'react-native-svg', and it looks like it has an issue with fontFamily

So, I might use this workaround

But in the meantime, what you can do, is to use the "render function" these components provide, like so:

import { Line } from 'react-native-svg'
import { Text } from 'react-native' // this is the trick

// later ...
<Marks>
  {(mark, i) => (
    <G key={i}>
      <Line
        {...mark.coordinates}
        // any other prop here, except x1, y1, x2, and y2
      />
      {(i % 2 == 0) && (
        // only show the number if the mark is even
        <Text
          {...mark.textProps}
          // any other prop here, except x, y, and transform
          style={{ fontFamily: 'roboto' }} // and here the second part of the trick
        >
          {mark.value}
        </Text>
      )}
    </G>
  )}
</Marks>

And the same for the indicator, if needed:

import { Text } from 'react-native' 

<Speedometer width={width}>
  <Indicator >
    {(value, textProps) => (
      <Text
        style={{
          fontFamily: 'roboto',
          position: 'absolute',
          top: width / 2 + 30, // (250 is the default width)
          fontSize: 40,
          textAlign: 'center',
          color: 'white',
          width: '100%',
        }}
      >
        {value}
      </Text>
    )}
  </Indicator>
</Speedometer>
EmilianoMorghen commented 2 years ago

You're great! Thanks for the help.

I was able to use a custom font but another issue appeared. Since with the trick of { Text } from "react-native" we don't use { Text } from "react-native-svg" the props x, y and transform are no longer supported.

So even if I can implement a custom font, marks will be rendered in rows. I've tried easy fixes by giving x and y to absolute positioned texts but it's not precise as it was without custom fonts. I've also noticed that when we pass custom marks to the Marks component it doesn't rotate the group loosing it's link with the "angle" prop set inside Speedometer component.

I'm looking forward for your feedback because maybe this behaviour isn't known. Keep rocking!

Example:

<Marks
  lineOpacity={0}
  numbersRadius={(8 * Dimensions.get("window").width) / 100}
  fontSize={12}
  step={props.maxValue / 10 / 2}
>
    {(mark, i) => (
      <G key={i}>
        {i % 2 == 0 && (
          // only show the number if the mark is even
         <Text
           {...mark.textProps}
           // any other prop here, except x, y, and transform
         >
             {mark.value}
         </Text>
         )}
      </G>
    )}
</Marks>
lucassaid commented 2 years ago

Exactly, yesterday I noticed that my trick didn't work with <Marks>, I spent like an hour trying to make it work without much success 😞

As you said the rotation inside SVG doesn't affect <Text> (from react-native) because is not a vector...

this is the closest I was to make it work

image

Maybe you can keep trying from this... Another option would be to have some hardcoded vectors like

const vectors = {
   '0': textProps => <path {...textProps} d="here your custom '0' " />,
   '10': textProps => <path {...textProps} d="here your custom '10' " />,
   ... and so on
}

Later you could do something like

{(mark, i) => (
  <G key={i}>
    {vectors[i] ? vectors[i](mark.textProps) : null}
  </G>
)}
lucassaid commented 2 years ago

Hey @EmilianoMorghen, I finally did it!

image

Note that I use "-125deg" and "125deg", I know this is the rotation because the default angle is 250. rotation is calculated from it (250 / 2). You might need another value other than "125" if you set a different angle or rotation

<Speedometer value={128}>
  <Background />
  <Arc/>
  <Needle/>
  <Progress/>
  {/* lines only */}
  <Marks lineSize={16}>
    {(mark, i) => (
      <Line
        key={i}
        {...mark.coordinates}
        strokeWidth={mark.isEven ? 3 : 2}
        stroke="white"
        opacity={0.6}
      />
    )}
  </Marks>
  {/* numbers only, wrapped into a rotated view */}
  <View style={{
    position: 'relative',
    width: '100%',
    height: '100%',
    transform: [
      { rotate: '-125deg'}
    ]
  }}>
    <Marks >
      {(mark, i) => (
        <Fragment key={i}>
          {i % 2 == 0 && (
            <Text
              style={{
                position: 'absolute',
                color: 'white',
                left: mark.textProps.x - 10,
                top: mark.textProps.y - 10,
                transform: [
                  { rotate: '125deg' },
                ]
              }}
            >
              {mark.value}
            </Text>
          )}
        </Fragment>
      )}
    </Marks>
  </View>
  <Indicator />
</Speedometer>
EmilianoMorghen commented 2 years ago

Hey @lucassaid, just implemented your solution and it works perfectly. I used View instead of Fragment but I think it's the same thing. Also I had a bit of troubles to position the outside view correctly but solved with absolute positioning.

Thank you again for your support, it was precious.

fatimaaaaah commented 1 year ago

Bonsoir, Votre composanr est vraiment utile.Je veux changer la couleur des graduations(10,20...).Est-ce possible ?