Как найти правильные значения для ширины, высоты и viewBox с помощью react-native-svg - PullRequest
1 голос
/ 07 мая 2020

Я пытался сделать что-то, что казалось простым, но я пытался несколько часов и не могу найти решение.

У меня есть SVG, который должен быть поверх экран. Он исходил от дизайнера со следующими размерами:

<Svg width="354px" height="190px" viewBox="0 0 354 190">...</Svg>

В React Native , это будет go внутри контейнера, а SVG должен занимать всю ширину экрана. , который я беру из:

Dimensions.get("window").width

Моя проблема в том, что я не нашел способа масштабировать SVG, чтобы он занимал 100% ширины экрана, выясняя правильную высоту (или способ он будет установлен автоматически) и сохранить соотношение сторон. Я пробовал миллион вещей, в том числе поигрался со стилем контейнера aspectRatio и его height (или вообще не задавая height ). Всякий раз, когда я находил какие-то «пропорции», которые работали, я пробовал использовать другое устройство с другой шириной экрана, и это выглядело совсем не очень хорошо (обрезано, меньше ширины экрана и т. Д. c).

Мне кажется, что свойство preserveAspectRatio в SVG (react-native-svg) каким-то образом конфликтует со стилем aspectRatio . И я совершенно потерялся с preserveAspectRatio , я не нашел способа масштабировать его без обрезки.

Кто-нибудь знает, как этого добиться?

Это мой последний код, который возвращает компонент HeatMap, показывающий SVG, но, хотя он имеет правильную высоту, часть SVG находится вне экрана справа (выглядит обрезанным, потому что он слишком широкий):

const windowWidth = Dimensions.get("window").width;

const getSVGRootProps = ({ width, height }) => ({
  width: "100%",
  height: "100%",
  viewBox: `0 0 ${width} ${height}`,
  preserveAspectRatio: "xMinYMin meet",
});

const FieldShape = () => {
  const width = 354; // Original width
  const height = 190; // Original height
  const aspectRatio = width / height;
  // adjusted height = <screen width> * original height / original width
  const calculatedHeight = (windowWidth * height) / width;
  const fieldStyles = {
    width: windowWidth,
    height: calculatedHeight,
    aspectRatio,
  };

  return (
    <View style={fieldStyles}>
      <Svg {...getSVGRootProps({ windowWidth, calculatedHeight })}>
      ...
      </Svg>
    </View>
  );
};

const HeatMap = () => {
  return <FieldShape />;
};

Это результат:

Result picture (pixelation intended)

1 Ответ

2 голосов
/ 14 мая 2020

Я нашел решение и публикую его здесь на случай, если кто-то столкнется с той же проблемой с react native и SVG. По сути, если вы пытаетесь получить файл SVG и превратить его в компонент с частями «Dynami c» (например, программно установить цвета для пути на основе данных или отобразить текст SVG), вы, вероятно, столкнетесь с этим проблема.

Я использовал SVGR для преобразования исходного SVG в собственный компонент реакции (с react-native-svg ). Затем я просто заменил жестко запрограммированные данные на переменные (из реквизита) по мере необходимости. Выглядело неплохо, но у меня возникла проблема с размером компонента. Я не мог найти единообразного способа отображать его на устройствах разных размеров и разрешений. Это казалось легким, но я пытался часами, и результаты были разными для каждого размера экрана. Спросив здесь и открыв вопрос о репозитории react-native-svg, я не получил ни ответов, ни подсказок (никого не обвиняю, просто сказал, что, возможно, это не то, с чем сталкиваются многие люди). Итак, я копал и копал и наконец нашел этот пост Лии Веру , где она говорила об абсолютных и относительных путях SVG. Это заставило меня подумать, что, возможно, у меня было так много проблем, пытаясь найти идеальную формулу изменения размера, потому что мои пути были не относительными, а абсолютными. Итак, я попробовал этот jsfiddle от heyzeuss , вставив свой (исходный) SVG-код, а затем скопировав результаты. Я вставил результаты в этот удобный инструмент SVGR (SVG в JS) , а затем изменил некоторые биты для достижения своей цели:

  • Я хочу, чтобы мой SVG принял

Итак, это то, что я изменил:

// SVG's original size is 519 width, 260 height
// <Svg width="519" height="260" viewBox="0 0 519 260">...</Svg>
// I also added a container, which enforces the aspect ratio
const originalWidth = 519;
const originalHeight = 260;
const aspectRatio = originalWidth / originalHeight;
const windowWidth = Dimensions.get("window").width;
return (
    <View style={{ width: windowWidth, aspectRatio }}>
        <Svg 
            width="100%" 
            height="100%" 
            viewBox={`0 0 ${originalWidth} ${originalHeight}`}>
        ...
        </Svg>
    </View>
)

Я узнал кое-что, делая это, например, что есть @ svgr / cli включен в приложение create-react-app, а также доступен в моем проекте, поддерживающем реакцию, без установки чего-либо дополнительного, поэтому он также должен быть связан с исходными зависимостями. Вы можете запустить эту команду, и она превратит отдельный файл или все файлы в папке из .svg в компоненты React:

npx @svgr/cli [-d out-dir] [--ignore-existing] [src-dir]

Скрипт, используемый для преобразования абсолютных путей к родственникам, является частью этой библиотеки, которая называется Snap.svg , но вам понадобится примерно 1% ( Snap.path.toRelative ). Я думаю о небольшом инструменте, который возьмет все пути в файле svg и применит это преобразование. Честно говоря, я имел дело с файлами SVG в течение многих лет, но я никогда не мог должным образом взглянуть на то, как они работают внутри, на формат путей, координат и так далее, так что это было очень поучительно :)

Надеюсь, это поможет вам, если вы окажетесь в такой же ситуации!

...