Страницы

Поиск по вопросам

воскресенье, 29 декабря 2019 г.

Чем опасен выход за границы массива?

#cpp #массивы


Можно ли оставлять выход за границы массива в программах? Чем это грозит? Что происходит
при выходе за его границы?
    


Ответы

Ответ 1



В современных операционных системах память каждого процесса существует отдельно от других процессов. Программа не может просто так получить доступ к памяти чужого процесса. Проверка осуществляется операционной системой, причём поддержка этого реализована аппаратно в современных процессорах. Это сделано для защиты, чтобы неправильно работающая программа не могла нарушить работу других. Представим память следующим образом: |___память_вашей_программы___массив|___память_чужой_программы___| В данном случае массив расположен в конце области памяти вашей программы. Если произойдёт выход за границу массива, то получится обращение к области памяти чужой программы. Операционная система этого не позволит, произойдёт исключение. А что если массив расположен так: |___сегмент_данных___массив\сегмент_кода___| В каждой программе есть сегмент(ы) кода и сегмент(ы) данных. На уровне операционной системы разным сегментам разрешены разные действия: чтение, запись, исполнение. Это, опять-таки, сделано для обеспечения надёжности. В сегмент кода запись запрещена. Соответственно, и в данном случае, если произойдёт обращение за пределами массива, тоже будет выброшено исключение. Третий вариант: |___сегмент_данных___массив___сегмент_данных___| В этом случае выход за пределы массивы не приведёт к исключению, операционная система не может отследить его своими силами, т. к. процесс имеет полное право писать в свой сегмент данных. Просто при этом будут либо прочитаны данные, не относящиеся к массиву, либо повреждены (переписаны) эти данные.

Избежание продублированного кода в конструкторах класса. С++

#cpp


class Boo
{
public:
    Boo()
    {
        Сделать X
    }
    Boo(int value)
    {
        Сделать Х
        СделатЬ У
    }
};


Например мне нужно сделать что-то в конструкторах. Причем в этих двух конструкторах
есть продублированный код. Насколько я знаю, есть два способа это избежать 

// 1 вариант
class Boo
{
public:
    Boo()
    {
        Сделать X
    }
    Boo(int value):Boo()
    {
        СделатЬ У
    }
};




// 2 Вариант

class Boo
{
public:
    Boo()
    {
        doX();
    }
    Boo(int value)
    {
        doX();
        Сделать У;
    }

    void doX()
    {
        Делает X;
    }
};


Какой из них лучше ? Почему ? Или может есть получше ?
    


Ответы

Ответ 1



Лучше_ это понятие относительное. Лучше, когда все соответствует вашим пожеланиям и пожеланиям и удобствам пользователей. Если пользователью может понадобится метод void doX(), то лучше второй вариант, потому что в первом нет этого метода, а если нет, то лучше первый вариант, поскольку в первом меньше вызовов функций. Конечно, в основном бывает полезнее вариант такой: class Boo { public: Boo(int value = 0) { Сделать X if (value ) СделатЬ У } }; Поскольку тут нет лишных вызовов(лучше в плане производительности) и меньше кода (лучше для читабельности и наверное компиляции). Тут разницы такие мизерные, что можно говорить в принципе только о читабельноси... Т.е. по возможности меньшим кодом нужно добится желаемого результата. Обновление: Еще раз говорю, все зависит от ваших намерений, потому что однозначно говорить как нужно, невозможно. Например если у меня есть такие тривиальные определения: void B() { std::cout << "I am Boo\n"; } void foo(int n) { std::cout << "i created with " << --n << '\n'; } class Boo { public: Boo(int value) { B(); foo(value); } Boo() { B(); } }; class His_variant { public: His_variant(int value) { B(); foo(value); } //разве это то, что я хотел выразить?... His_variant() : His_variant(0) {} }; class My_version { public: My_version(int value = 0) { B(); if (value) foo(value); } }; То, если мы напишем программу: // первый вариант Boo b, bb(22); std::cout <<"\n----------------" << std::endl; // вариант с другого ответа His_variant h, hh(22); std::cout <<"\n----------------" << std::endl; // вариант, о котором говорил я My_version m, mm(22); Первыи и третий вариант выдадут одинаковый результат, с той разницей, о чем я говорил, а вариант второй(о чем говорилось в другом ответе), естественно, выдаст совершенно другой результат

Ответ 2



Если "действия", о которых вы говорите, должны производиться именно в теле конструктора (между {}), то никакой принципиальной разницы между этими подходами нет. Второй вариант лишь заводит лишнюю сущность - дополнительный метод класса. Если закрыть на это глаза, то без разницы как делать. Но тут надо заметить, что в конструкторе в первую очередь нас интересует устранение повторений в списке инициализации, т.е. именно для class Boo { public: Boo(x, y) : хитро_инициализировать_A(x, y), хитро_инициализировать_B(x, y) {} Boo() : хитро_инициализировать_A(3, 42), хитро_инициализировать_B(3, 42) {} }; Раньше нам приходилось извращаться через class Boo { public: Boo(x, y) : // "Ложная" инициализация, возможно неявная инициализировать_A_какой-то-хренью, инициализировать_B_какой-то-хренью { do(x, y); } Boo() : // "Ложная" инициализация, возможно неявная инициализировать_A_какой-то-хренью, инициализировать_B_какой-то-хренью { do(3, 42); } void do(x, y) { // Вторая, "настоящая" инициализация хитро_переинициализировать_A_по-новому(x, y); хитро_переинициализировать_B_по-новому(x, y); } }; Т.е. в этом варианте A и B в общем случае сначала пройдут через некую инициализацию "по умолчанию", а затем - через дополнительную "доинициализацию" (или "переинициализацию") уже в функции. Это нерационально. Это неприятное явление известно как проблема двойной инициализации. И к тому же этот подход вообще невозможно никак применить для полей, не допускающих инициализацию по умолчанию или переинициализацию (поля-ссылки, константные поля и т.п.) Вот тут-то нам и приходит на помощь ... Boo() : Boo(3, 42) {} ... Этот вариант был введен в язык "относительно недавно" в первую очередь для того, чтобы решить вышеописанную проблему двойной инициализации. Подход с делегирующим вызовом конструктора свободен от этого недостатка. Выполняется именно инициализация и выполняется она ровно один раз.

Прозрачный текст с белым бордером

#css #svg #текст


Каким образом достичь данного результата? 



Способы:

color: rgba(255,255,255,0.01)
background-clip
color: transparent + text-shadow


Не дали результатов
    


Ответы

Ответ 1



Можно с помощью svg: body { background: #b4e391; background: -moz-linear-gradient(-45deg, #b4e391 0%, #61c419 50%, #b4e391 100%); background: -webkit-linear-gradient(-45deg, #b4e391 0%, #61c419 50%, #b4e391 100%); background: linear-gradient(135deg, #b4e391 0%, #61c419 50%, #b4e391 100%); filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#b4e391', endColorstr='#b4e391', GradientType=1); } Ваш текст

Ответ 2



А как же старый добрый -webkit-text-stroke? Вроде уже и поддержка неплохая. Может я чего-то не понял, но в метках есть [CSS], а это он самый, в чистом виде и с минимумом кода: body { background: url(http://lorempixel.com/600/600/) no-repeat; font: bold 96px 'Arial Black'; text-align: center; } .txt-1 { color: rgba(255, 141, 0, 0.0); -webkit-text-stroke: 1px white; } .txt-2 { color: rgba(255, 141, 0, 0.38); -webkit-text-stroke: 1px black; } .txt-3 { color: rgba(128, 255, 0, 0.38); -webkit-text-stroke: 4px red; } SYSTEM
SYSTEM
SYSTEM

Ответ 3



Используйте значение rgba() для свойства color div { font-family: Arial Black, Arial Bold, Gadget, sans-serif; color: rgba(255, 255, 255, 0.4); font-size: 80px; margin-left: 25px; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; }
Некоторый текст
Или вы можете использовать :pseudo-element. div { position: relative; font-family: Arial Black, Arial Bold, Gadget, sans-serif; font-size: 80px; margin-left: 25px; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; } div:after { position: absolute; top: 0; left:0; content: 'Некоторый текст'; width: 100%; height: 100%; font-family: Arial Black, Arial Bold, Gadget, sans-serif; color: white; opacity: 0.4; font-size: 80px; z-index: 1; pointer-events: none; }
Некоторый текст
Или вы можете использовать SVG. body, html { height: 100%; margin: 0; background: url(http://lorempixel.com/500/200/) no-repeat; } Некоторый текст Перевод ответа со Stack Overflow на английском

Ответ 4



Попробуй с помощью псевдо элементов: div { position: relative; font-family: Arial Black, Arial Bold, Gadget, sans-serif; font-size: 80px; margin-left: 25px; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; } div:after { position: absolute; top: 0; left:0; content: 'Some text'; width: 100%; height: 100%; font-family: Arial Black, Arial Bold, Gadget, sans-serif; color: white; opacity: 0.4; font-size: 80px; z-index: 1; pointer-events: none; } Источник с другими решениями

Что происходит с объектом после std::move?

#cpp #cpp11 #move


Пример класса: 

class Move
{
   public:
   Move(std::string name) : name(name) {};
   Move(Move&& move) : name(std::move(move.name)) {};
   void Set(std::string&& add)
   {
      this->name.append(add);
   }
   void Print()
   {
      std::cout << this->name << std::endl;
   }

private:
   std::string name;
};


После выполнения данного кода: 

Move move0("string");
Move move1 = std::move(move0);


объект move0 будет иметь вид {name=""}, но "" пустая std::string все равно занимает
место в памяти и не освобождает ее сама по себе. Получается, что перемещение более
эффективное в некоторых случаях, но при этом старые ссылки остаются "доживать" свой
век? Не понятно, что происходит с объектами после использования на них std::move, хотя
казалось бы, что они должны становиться nullptr. 

UPD

Почему есть ситуации  в которых после std::move объект из которого было произведено
перемещение, остается без изменений? 

int main()
{
   std::string str = " Another";
   m.Set(std::move(str));
   return 0;
}


После std::move(str), сам str остался без изменений. 
    


Ответы

Ответ 1



С++ - это вам не Java. В нем объекты не могут быть null, и не являются ссылками. что происходит с объектами после использования на них std::move Строго говоря, move ничего не делает, кроме как превращает выражение в rvalue ("маскирует" под временную переменную). Это влияет в первую очередь на разрешение перегрузок, и в том числе заставляет срабатывать перемещающие конструктор и оператор присваивания, вместо копирующих. Изменения в объекте вызываются именно перемещающими конструктором или оператором присваивания, куда он передается как аргумент (если это вообще происходит). Что конкретно происходит с объектом после перемещения из него - зависит того, как написаны перемещающие конструктор и оператор присваивания. Про стандартные контейнеры, например, говорят что они "are left in valid, but unspecified state". В большинстве реализаций они становятся пустыми, но это не гарантируется. казалось бы, что они должны становиться nullptr. Объекты нельзя "сделать nullptr", но можно переформулировать вопрос: Почему перемещение из объекта не уничтожает его, и требуется дополнительный вызов на нем деструктора? Я так понимаю, потому что это очень усложнило бы работу компилятора. Например, для void foo(std::string s) { // ... } деструктор всегда вызывается для s при возврате из функции. А если перемещение из объекта уничтожало бы его, то компилятору потребовалось бы отслеживать, какие переменные перемещаются, а какие нет. Если переменные перемещаются при определенном условии, то пришлось бы запоминать для каждого объекта, был он перемещен или нет, и в зависимости от этого вызывать или не вызывать на нем деструктор при выходе из функции. Это выглядит сложно.

Ответ 2



В языке С++ нет никакой встроенной семантики перемещения. В языке С++ есть только rvalue-ссылки, категории результатов выражений, и связанные с ними правила overload resolution. А что вы сами "слепите" из этих базовых свойств языка - семантику перемещения или что-то другое - определяется только вашим кодом (или, соответственно, библиотечным кодом). Вы передали переменную str в метод Set по rvalue-ссылке, ни внутри метода Set вы только копируете полученный аргумент add и никакого физического перемещения данных из него даже и не пытаетесь делать. Если вы "надеетесь" получить физическое перемещение из add внутри метода Set, то это ваша задача - разрешить методу std::string::append переместить данные из своего аргумента void Set(std::string&& add) { this->name.append(std::move(add)); } Но и в этом случае фактическое перемещение данных из add произойдет только в том случае, если сам метод std::string::append примет решение выполнить перемещение. И здесь я вам могу сказать по секрету, что метод std::string::append в принципе никогда ничего не перемещает. В большинстве применений std::string::append это просто-напросто невозможно. Оптимизировать std::string::append через физическое перемещение возможно только в том случае, когда строка-получатель изначально пуста. А это слишком частная ситуация, чтобы ее оптимизировать. (Я бы лично, возможно, это сделал, но разработчики класса std::string рассудили по-другому.) И постарайтесь уяснить, что в С++ обычное копирование - это тоже один из вариантов перемещения. Поэтому рассуждения вроде "объект остался неизменным, значит перемещения не произошло" - бессмысленны.

Для чего нужны файлы устройств?

#linux #c #драйвер


Чтобы использовать символьный драйвер - нам надо создать файл устройста, он же специальный
файл или узел дерева файловой системы. У меня есть два мнения для чего он нужен, скажите,
пожалуйста, какое правильное (если есть такое).

1) Это файл, который служит неким интерфейсом. Например, когда мы пишем такую команду
echo "hello" > /dev/my_driver, то строка "hello" пишется не в сам файл /dev/my_driver,
а в некий буфер, который нам предоставляет ядро. Так-же с функциями open, read и тд.,
они не открывают сам файл, а просто сигнализируют, что надо создать и открыть некий
файл или прочитать данные. 

2) Это обычный файл, в который мы записываем данные и читаем их оттуда же. При той
же команде echo "hello" > /dev/my_driver, строка "hello" запишется непосредственно
в файл /dev/my_driver. 
    


Ответы

Ответ 1



tl;dr Правильный вариант, скорее, — (1); чтение/запись обрабатывается непосредственно драйвером устройства, промежуточного буфера может и не быть (хотя обычно он есть в пространстве ядра). Что вообще происходит при вызовах open()/read() итд? При системном вызове open() в массив файловых дескрипторов (current->files->fdt->fd), связанный со структурой текущего работающего процесса (current), помещается новая запись (struct fd), которая содержит структуру отождествляемую с открытым файлом (struct file). При этом в поле данной структуры f_op записывается набор операций, которые можно делать с данным файлом (struct file_operations). В итоге вызов open() просто возвращает номер новой выделенной записи в вышеупомянутом массиве. Вызов read() по сути просто достаёт файловых дескриптор из массива с помощью fdgetpos(), проверяет права доступа на чтение/запись и вызывает уже заданную связанную с файлом операцию чтения. Аналогично работают и все прочие вызовы — write/mmap/ioctl итп. Так чем же отличается чтение из обычного файла и из файла-устройства? По сути ни чем: единственное различие в том, что набор операций (struct files_struct) при открытии берётся не от драйвера файловой системы, а от драйвера устройства. Аналогичным образом реализованы и файлы в псевдо-файловых-cистемах /proc и /sys.

Ответ 2



Если говорить о файлах устройств (есть ещё и другие псевдофайлы), то отличие их от обычных ("регулярных") файлов заключается в том, что: регулярные файлы существуют в физической реальности. После записи байта в такой файл мы можем найти место в физическом мире, где этот байт лежит. псевдофайлы (в том числе и файлы устройств) физически не существуют. После записи байта в файл /dev/ttys0 этот байт не присутствует нигде в реальном мире. Совершенно аналогичная ситуация с псевдофайлами из каталогов /proc, /sys и т.д. Запись в эти файлы (при наличии прав доступа) приводит к измению поведения ОС, а вовсе не к тому, что записанный (якобы) байт где-то сохранился. Несколько особая ситуация с псевдофайлами устройств дисковых накопителей. Хотя для /dev/sda1 можно выполнять операции чтения/записи, вот только результат будет довольно неожиданный, так как операции ввода/вывода будут выполняться не с файлами (расположенными ВНУТРИ диска), а с блоками, образующими ФС этого диска. Совершенно особая песня - псевдофайлы сетевых карточек, разделяемой памяти и т.д. которые используются исключительно для управления этими устройствами, а операции ввода/вывода выполняются специальными IOCTL командами, образующими систему сокетов. Короче - это всё сложная и большая тема.

matplotlib разделить маркеры

#python #графика #matplotlib


Есть файл CSV вида 

1,0,enp0s31f6
1,0,enp0s31f6
2,0.286968124,enp0s31f6
3,0.347273802,enp0s31f6
4,0.376051415,enp0s31f6
5,1.895804954,enp0s31f6
6,2.03941807,eth0
7,2.061084575,enp0s31f6
8,3.026748561,enp0s31f6
9,3.247024689,enp0s31f6
10,3.896585252,eth0
11,4.001361629,enp0s31f6
12,4.216054934,enp0s31f6
13,4.26913004,eth0
14,4.26942665,enp0s31f6
15,4.463316773,enp0s31f6


Рисую график вот так:


import matplotlib.pyplot as plt
import csv

x = []
y = []

with open('test.csv','r') as csvfile:
    plots = csv.reader(csvfile, delimiter=',')
    for row in plots:
        x.append(int(row[0]))
        y.append(float(row[1]))

plt.scatter(x,y, marker='o', label='Interfaces')
plt.xlabel('Packets')
plt.ylabel('Time')
plt.title('TEST')
plt.legend()
plt.show()




Получаю на выходе:



Но на данной картинке только 1 вид маркеров (enp0s31f6 и eth0) вместе, как разделить
их? Чтобы , к примеру, enp0s31f6 был синим маркером, а eth0 - оранжевым. 
    


Ответы

Ответ 1



В первую очередь необходимо разделить исходные данные по признаку принадлежности к конкретному интерфейсу. Для этого можно использовать словарь, но так как чтение происходит из csv формата, удобнее будет воспользоваться готовыми инструментами (numpy, pandas). Например, функция recfromcsv из numpy позволяет получить исходные данные в виде numpy.recarray с автоматическим определением типов. import matplotlib.pyplot as plt import numpy as np data = np.recfromcsv('test.csv', encoding=None, names=('time', 'packets', 'interface')) # если в реальности интерфейсов будет больше, то надо добавить цветов colors = 'blue', 'orange' ifaces = np.unique(data.interface) # множество интерфейсов assert len(colors) == ifaces.size for color, iface in zip(colors, ifaces): # получение данных, относящихся к текущему интерфейсу items = data[data.interface == iface] plt.scatter(items.time, items.packets, marker='o', label=iface, color=color) plt.xlabel('Packets') plt.ylabel('Time') plt.title('TEST') plt.legend() plt.show()

Ответ 2



import matplotlib.pyplot as plt import csv x = [] y = [] cl= [] # + with open('test.csv','r') as csvfile: plots = csv.reader(csvfile, delimiter=',') for row in plots: x.append(int(row[0])) y.append(float(row[1])) cl.append('r' if row[2]=='eth0' else 'g') # + plt.scatter(x,y, marker='o', c=cl, label='Interfaces') # + c=cl plt.xlabel('Packets') plt.ylabel('Time') plt.title('TEST') plt.legend() plt.show()

Ответ 3



По-моему проще всего решить эту задачу используя Pandas: import numpy as np import pandas as pd df = pd.read_csv(r'C:\Temp\test.csv', header=None, names=['x','y','name']) df['col'] = np.where(df['name'] == 'enp0s31f6', 'blue', 'orange') df.plot.scatter(x='x', y='y', c=df['col'])

Анимация заливки термометра svg + jquery

#javascript #html #jquery #svg #svg_animation




Хочу сделать свг градусник и чтобы при нажатии на чекбоксы, заливка проводилась плавно
снизу вверх, включая деления термометра(следовательно когда галочки будут снимать то
заливка будет так же плавно спускаться). Интересует как сделать такую заливку и прикрутить
jquery для этого. (Чекбоксы работают по принципу toogleClass("check")).

Вот что я смог напортачить в Jquery

$(".analysis-li").click(function(){
    $(this).toggleClass("check");
    var firstStop = document.getElementById('F1gst1');
    percentage = '10%'; firstStop.setAttribute('offset',percentage);
});


Нужно сделать чтобы при каждом классе check процент увеличивался, а при убирание
этого класса, он опять уменьшался. Ниже html и css

  • li.analysis-li margin-bottom: 54px position: relative padding-left: 20px cursor: pointer &::before position: absolute content: '' width: 34px height: 34px left: -34px bottom: 3px border: #d3ad4b solid 3px background-color: transparent cursor: pointer background-image: url(../img/check.png) background-repeat: no-repeat background-position: center background-size: 0 &.check::before background-size: 30px &:hover::before border-color: #c29846 transition: .3s


    Ответы

    Ответ 1



    Вот собрал что-то подобное, извиняйте уж без жуквери, изменил верстку на программную, если это не надо можно скопировать готовый html из сниппета через отладчик let path = (y, d, extra) => `` let multi = (count, html) => Array(count).fill(0).map((e, i) => html(i)).join(''); let toggle = el => el.classList.toggle('on') | rect.setAttribute('y', 14.6*(7-document.querySelectorAll("path.on").length)+8) scale.innerHTML = multi(10, i => path(i*10, 'M60,10h10M65,12h5M65,14h5M65,16h5M65,18h5')); checks.innerHTML = multi(7, i => path(i*12, 'M10,10v8h8v-8z', 'class="on" onclick="toggle(this)"') + path(i*12, 'M12,14l2.2,2l2.2,-4')) g#scale path { stroke: white; stroke-width: 0.7; } #checks { position: absolute; top: 20px; left: 20px; } #checks path { fill: none; pointer-events: all; stroke: #f5b53a; cursor:pointer; stroke-linejoin:round; } #checks path.on + path { opacity:1; } #checks path:nth-child(2n) { opacity: 0; pointer-events: none; transition: 0.5s; stroke: white; }

    Ответ 2



    В общем вот так примерно Смотреть на полный экран let move = cb => rect.setAttribute('y', 400 - cb.textContent*50) document.querySelectorAll('.checkbox') .forEach(cb => cb.addEventListener('click', e => move(cb))) * { user-select: none; } html, body { height: 100%; margin: 0; padding: 0; } .text { font-size: 20px; fill: #fff; font-weight: 900; font-family: Georgia, 'Times New Roman', Times, serif; } .svg-event { width: 800px; position: relative; margin: 30px auto; } .panel { position: absolute; top: 30px; left: 30px; width: 100px; height: 500px; } .panel div { width: 50px; height: 50px; background: #fbfbfb; margin: 18px auto; display: flex; justify-content: center; align-items: center; font-family: 'Times New Roman', Times, serif; font-weight: 900; } #rect { transition: 0.68s cubic-bezier(0.05, 1.06, 0.71, 0.4); }
    7 6 5 4 3 2 1 Высокая темпиратура Средняя темпиратура Низкая темпиратура
    7
    6
    5
    4
    3
    2
    1


    Ответ 3



    Решение jQuery Вот как бы я это сделал. Для анимации градиента я использую requestAnimationFrame. Я анимирую второе смещение stop между 10% и 100%, но вы можете выбрать нужные значения. Пожалуйста, прочитайте комментарии в коде. // Второй stop градиента let laststop = document.getElementById('F1gst2'); // переменная, используемая для переключения анимации let n = 0; // целевое значение атрибута смещения let target; // фактическое значение атрибута смещения (offset) let val = 10; //идентификатор кадра анимации запроса let rid = null; $(".analysis-li").click(function(){ n++; // установить целевое значение if(n%2 == 1){ target = 100; }else{target = 10} // если есть анимация, то остановить if(rid){cancelAnimationFrame(rid); rid="null"} // вызвать функцию кадра frame() }); function frame(){ rid = requestAnimationFrame(frame); //расстояние между значением и целевым значением dist = target - val; //Увеличить значение val += dist/10; // установить значение offset laststop.setAttributeNS(null,"offset",`${val}%`) } svg{border:1px solid; width:30px} path{stroke:black;}

    click here

    Аналогичный вопрос был задан на EnSo. Источник ответа: @enxaneta Сделал перевод и размещаю его здесь для более полной картины возможностей решения. Чем больше ответов, тем полезнее для поиска нужного решения.

    Ответ 4



    Разобрался с помощью установки градиента. Не забудьте удалить тэг style в svg если он у вас есть. Градиент вставляется после открывающего тега svg перед path. Потом при помощи offset добился заливки в процентах. Потом идет сравнивание количество элементов и количество выбранных элементов. И после этого задается результат. var firstStop = document.getElementById('F1gst1'); percentage = '0%'; var CountAllCheckboxes = $('.analysis-li').length; var CountChecked = 0; $(".analysis-li").click(function(){ $(this).toggleClass("check"); CountChecked = $('.analysis-li.check').length; percentage = ((CountChecked / CountAllCheckboxes) * 100)+'%'; firstStop.setAttribute('offset',percentage); }); Решение с плавной анимацией https://stackoverflow.com/a/56836400/11707220