SVG Линейный градиент Фон SVG

Я пытаюсь использовать SVG, который будет динамически создаваться из JavaScript, в качестве фонового изображения на другом SVG. Это работает, когда цвет заливки объекта сплошной, но не когда я пытаюсь использовать линейный градиент. Запустите код, чтобы увидеть пример. Пожалуйста, помогите понять, как использовать линейный градиент!

        const createElement = (tag, attributes) => {
            const element = document.createElement(tag);
            if (attributes) Object.keys(attributes).forEach(key => element.setAttribute(key, attributes[key]));
            return element;
        }

        // Create background for first SVG using solid color fill:
        const svg3bg = createElement('svg', { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 50 50', width: 50, height: 50 });
        svg3bg.appendChild(createElement('circle', { cx: 25, cy: 25, r: 20, fill: '#00F' }));
        const svg3 = document.getElementById('svg3');
        svg3.style.backgroundImage = `url('data:image/svg+xml,${svg3bg.outerHTML.replace(/\#/g, '%23')}')`; // This does not display unless I replace the # signs with a hex code.
        svg3.style.backgroundColor = 'palegreen';

        // Create background for second SVG using linear gradient fill:
        const svg4bg = createElement('svg', { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 50 50', width: 50, height: 50 });
        const lg4 = svg4bg.appendChild(createElement('linearGradient', { id: "lg4" }))
        lg4.appendChild(createElement('stop', { offset: "0%", 'stop-color': '#d67ef5' }))
        lg4.appendChild(createElement('stop', { offset: "50%", 'stop-color': '#2b78ba' }))
        lg4.appendChild(createElement('stop', { offset: "100%", 'stop-color': '#4d79a9' }))
        svg4bg.appendChild(createElement('circle', { cx: 25, cy: 25, r: 20, fill: 'url(#lg4)' }));
        const svg4 = document.getElementById('svg4');
        svg4.style.backgroundImage = `url('data:image/svg+xml,${svg4bg.outerHTML.replace(/\#/g, '%23')}')`;
        svg4.style.backgroundColor = 'palegreen';
    This shows an SVG using another SVG (generated from JavaScript) of blue dots as its background image:
    <div id="div3">
        <svg id="svg3" iewBox="0 0 100 100" style="width: 150; height: 150;">
            <rect x="10" y="10" width="80" height="80" style="stroke: black; fill: none; stroke-width: 4"></rect>
        </svg>
    </div><br>
    When trying to do the same thing with a linear gradient to fill the object instead of a solid color, it does not
    display:
    <div id="div4">
        <svg id="svg4" iewBox="0 0 100 100" style="width: 150; height: 150;">
            <rect x="10" y="10" width="80" height="80" style="stroke: black; fill: none; stroke-width: 4"></rect>
        </svg>
    </div><br>
    This shows what the background image with the linear gradient should look like:
    <div id="div5">
        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 50 50" width="50" height="50">
            <lineargradient id="lg5">
                <stop offset="0%" stop-color="#d67ef5"></stop>
                <stop offset="50%" stop-color="#2b78ba"></stop>
                <stop offset="100%" stop-color="#4d79a9"></stop>
            </lineargradient>
            <circle cx="25" cy="25" r="20" fill="url(#lg5)"></circle>
        </svg>
    </div>


person Adam Sassano    schedule 09.03.2021    source источник


Ответы (1)


Мне кажется, нормально, когда я исправляю все опечатки.

  • В viewBox в некоторых местах отсутствует буква v
  • единицы отсутствуют в размерах CSS, где они являются обязательными
  • используйте createElementNS для создания элементов SVG и используйте сериализатор XML вместо сериализации HTML для получения пространств имен в выходных данных.
  • хотя в этом случае это не обязательно, я исправил кодировку URI должным образом, а не использовал замену

const createElement = (tag, attributes) => {
            const element = document.createElementNS('http://www.w3.org/2000/svg', tag);
            if (attributes) Object.keys(attributes).forEach(key => element.setAttribute(key, attributes[key]));
            return element;
        }

        let s = new XMLSerializer();
        // Create background for first SVG using solid color fill:
        const svg3bg = createElement('svg', { viewBox: '0 0 50 50', width: 50, height: 50 });
        svg3bg.appendChild(createElement('circle', { cx: 25, cy: 25, r: 20, fill: '#00F' }));
        const svg3 = document.getElementById('svg3');
        svg3.style.backgroundImage = `url('data:image/svg+xml,${encodeURIComponent(s.serializeToString(svg3bg))}')`;
        svg3.style.backgroundColor = 'palegreen';

        // Create background for second SVG using linear gradient fill:
        const svg4bg = createElement('svg', { viewBox: '0 0 50 50', width: 50, height: 50 });
        const lg4 = svg4bg.appendChild(createElement('linearGradient', { id: "lg4" }))
        lg4.appendChild(createElement('stop', { offset: "0%", 'stop-color': '#d67ef5' }))
        lg4.appendChild(createElement('stop', { offset: "50%", 'stop-color': '#2b78ba' }))
        lg4.appendChild(createElement('stop', { offset: "100%", 'stop-color': '#4d79a9' }))
        svg4bg.appendChild(createElement('circle', { cx: 25, cy: 25, r: 20, fill: 'url(#lg4)' }));
        const svg4 = document.getElementById('svg4');
        svg4.style.backgroundImage = `url('data:image/svg+xml,${encodeURIComponent(s.serializeToString(svg4bg))}')`;
        svg4.style.backgroundColor = 'palegreen';
This shows an SVG using another SVG (generated from JavaScript) of blue dots as its background image:
    <div id="div3">
        <svg id="svg3" viewBox="0 0 100 100" style="width: 150px; height: 150px;">
            <rect x="10" y="10" width="80" height="80" style="stroke: black; fill: none; stroke-width: 4"></rect>
        </svg>
    </div><br>
    When trying to do the same thing with a linear gradient to fill the object instead of a solid color, it does not
    display:
    <div id="div4">
        <svg id="svg4" viewBox="0 0 100 100" style="width: 150px; height: 150px;">
            <rect x="10" y="10" width="80" height="80" style="stroke: black; fill: none; stroke-width: 4"></rect>
        </svg>
    </div><br>
    This shows what the background image with the linear gradient should look like:
    <div id="div5">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="50" height="50">
            <linearGradient id="lg5">
                <stop offset="0%" stop-color="#d67ef5"></stop>
                <stop offset="50%" stop-color="#2b78ba"></stop>
                <stop offset="100%" stop-color="#4d79a9"></stop>
            </linearGradient>
            <circle cx="25" cy="25" r="20" fill="url(#lg5)"></circle>
        </svg>
    </div>

person Robert Longson    schedule 09.03.2021
comment
Интересно, что я пробовал createElementNS, но когда я также использовал externalHTML, он не включал атрибут xmlns в вывод. Кроме того, при использовании createElementNS я не могу добавить атрибут xmlns с помощью setAttribute или setAttributeNS. Вот почему я перешел на createElement, чтобы просто добавить атрибут xmlns вручную. Но теперь я вижу, что при использовании createElementNS в сочетании с encodeURIComponent вместо outerHTML атрибут xmlns включается. Следовательно, encodeURIComponent действительно является частью решения вместе с использованием createElementNS. - person Adam Sassano; 09.03.2021
comment
Незначительное примечание: если вам не требуется значение appendChild( element ) return. Затем выгрузите все эти операторы и используйте append, он принимает несколько аргументов (или распространяет массив). См .: developer.mozilla.org/en-US/docs/Web/API/ParentNode/append - person Danny '365CSI' Engelman; 09.03.2021
comment
@AdamSassano - это действительно его serializeToString, который сохраняет пространство имен и заменяет внешний HTML. encodeURIComponent заменяет функцию замены. - person Robert Longson; 09.03.2021
comment
Большое спасибо за разъяснения. - person Adam Sassano; 09.03.2021