价格行为的滚动过渡动画。如何?
Scrolling transition animation for price action. How?
我在网上查了一下,只找到了 swift
的版本。在网上,returns 搜索结果的唯一关键字是 ScrollCounter。这种类型的动画是否可能 CSS
HTML
?
如果有人可以向我指出有效的资源或示例,我将在创建有效示例后post支持我的研究。
看看
并混淆 CSS 和 HTML...
更新 1
我找到了以下计数器动画,但仍在尝试弄清楚如何将其实现为货币计数器,包括用于大于 999.99 的数字的可选逗号。
尽管...在现实生活中,我会通过 WebSockets 更新此值。
const genNumber = () => {
document.querySelector("div").style.setProperty("--percent", Math.random());
};
setInterval(genNumber, 3000);
setTimeout(genNumber);
@property --percent {
syntax: "<number>";
initial-value: 0;
inherits: false;
}
@property --temp {
syntax: "<number>";
initial-value: 0;
inherits: false;
}
@property --v1 {
syntax: "<integer>";
initial-value: 0;
inherits: false;
}
@property --v2 {
syntax: "<integer>";
initial-value: 0;
inherits: false;
}
div {
font: 800 40px monospace;
padding: 2rem;
transition: --percent 1s;
--temp: calc(var(--percent) * 100);
--v1: max(var(--temp) - 0.5, 0);
--v2: max((var(--temp) - var(--v1)) * 100 - 0.5, 0);
counter-reset: v1 var(--v1) v2 var(--v2);
}
div::before {
content: counter(v1) "." counter(v2, decimal-leading-zero) "%";
}
<div></div>
我修改了第一个答案,使其在语义上更合理。一路上添加了评论和解释,因为我发现@Phillip Rollins 的方法非常聪明。
// Usage
// Reference to div element that is going to be used as the spinner
const spinnerContainer = document.getElementById('BTCUSD');
spinnerContainer.setAttribute('class', 'spinner-container');
// INITITAL CONSTRUCT
// Array that contains div with class spinner-col HTML elements
const spinnerColumns = [];
// The View will contain the following possible characters
const spinnerCharacters = ['$', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', ','];
// Assumed total length of 12 digits...
for (let i = 0; i < 12; i++) {
// Create Anonymous div
spinnerColumns[i] = document.createElement('div');
// Set Anonymous div class to spinner-col
spinnerColumns[i].setAttribute('class', 'spinner-col');
// For each character in array spinnerCharacters...
for (let spinnerCharacter of spinnerCharacters) {
// Create Anonymous div
const div = document.createElement('div');
// ..containing this character
div.innerText = spinnerCharacter;
// Set Anonymous div class to spinner-char
div.setAttribute('class', 'spinner-char');
// Append Anonymous div spinner-char to Anonymous div spinner-col
spinnerColumns[i].append(div);
}
// Append Anonymous div spinner-col to spinner-container
spinnerContainer.append(spinnerColumns[i]);
}
// RENDER LOGIC
// Set spinner value to number passed in
const setSpinnerValue = (spinnerValue) => {
// The amount of column.style.display = 'none' attributes to initialize
// is equivalent to the amount of digits in the number passed in
for (let i = spinnerValue.length; i < spinnerColumns.length; i++) {
// initially NOT visible
spinnerColumns[i].style.display = 'none';
}
// The amount of column.style.display = 'block' attributes to update
// is equivalent to the amount of digits in the number passed in
for (let i = 0; i < spinnerValue.length; i++) {
const index = spinnerCharacters.indexOf(spinnerValue[i]);
// NOW visible
spinnerColumns[i].style.display = 'block';
// Apply CSS transform style
spinnerColumns[i].style.transform = `translate(0, -${index * 75}px)`;
}
};
// A currency formatter for setting the spinner value
const formatCurrency = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
});
// PRICE FEED
// Just a timer setting random prices every 2 seconds
// Easily replaceble with polling or websockets
setInterval(() => {
const spinnerValue = Math.random() * (999999 - 100000) + 100000;
// Update Price
setSpinnerValue(formatCurrency.format(spinnerValue / 100));
}, 2000);
.spinner-container {
height: 75px;
display: flex;
overflow: hidden;
}
.spinner-col {
box-sizing: border-box;
transform: translate(0, 0);
transition: transform 800ms ease-in-out;
}
.spinner-char {
width: 34px;
text-align: center;
font-size: 50px;
height: 75px;
line-height: 75px;
}
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous">
<div id="BTCUSD"></div>
<h4>BTCUSD</h4>
这是我设法想出的,希望比您自己的答案更符合您的要求。只需创建所有可能的字符,然后使用 CSS 将正确的字符滚动到视图中。
(() => {
// BUILD VIEW
const chars = ["$", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", ','];
const formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
});
const container = document.createElement("div");
container.setAttribute("class", "spinner-container");
const cols = [];
for (let x = 0; x < 12; x++) {
cols[x] = document.createElement("div");
cols[x].setAttribute("class", "spinner-col");
for (let char of chars) {
const div = document.createElement("div");
div.innerText = char;
div.setAttribute("class", "spinner-char");
cols[x].append(div);
}
container.append(cols[x]);
}
document.body.append(container);
// LOGIC
const setValue = (value) => {
for (let x = value.length; x < cols.length; x++) {
cols[x].style.display = "none";
}
for (let x = 0; x < value.length; x++) {
const index = chars.indexOf(value[x]);
cols[x].style.display = "block";
cols[x].style.transform = `translate(0, -${index * 75}px)`;
}
};
setInterval(() => {
const value = Math.random() * (999999 - 100000) + 100000;
setValue(formatter.format(value / 100));
}, 2000);
})();
.spinner-container {
height: 75px;
display: flex;
overflow: hidden;
}
.spinner-col {
box-sizing: border-box;
transform: translate(0, 0);
transition: transform 400ms ease-in-out;
}
.spinner-char {
width: 34px;
text-align: center;
font-size: 50px;
height: 75px;
line-height: 75px;
}
抱歉双重回答,这是对我的另一个回答的扩展,不想增加原始回答的复杂性。使用自定义元素,我们可以使其可重复使用。
const chars = ["$", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", ','];
class RHPriceElement extends HTMLElement {
static get observedAttributes() {
return ['value'];
}
constructor() {
super();
this.formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
});
this._build();
}
attributeChangedCallback(name, _oldValue, newValue) {
if (name === "value") {
const value = this.formatter.format(newValue);
while (this.cols.length < value.length) this._addCol();
for (let x = value.length; x < this.cols.length; x++) {
this.cols[x].style.display = "none";
}
for (let x = 0; x < value.length; x++) {
const index = chars.indexOf(value[x]);
this.cols[x].style.display = "block";
this.cols[x].style.transform = `translate(0, -${index * 75}px)`;
}
}
}
_build() {
this.cols = [];
for (let x = 0; x < 12; x++) {
this._addCol();
}
}
_addCol() {
const x = this.cols.length;
this.cols[x] = document.createElement("div");
this.cols[x].setAttribute("class", "spinner-col");
for (let char of chars) {
const div = document.createElement("div");
div.innerText = char;
div.setAttribute("class", "spinner-char");
this.cols[x].append(div);
}
this.append(this.cols[x]);
}
}
customElements.define('rh-price', RHPriceElement);
(() => {
setInterval(() => {
document.querySelectorAll("rh-price").item(0).setAttribute("value", Math.random() * (9999999 - 10000) + 10000);
document.querySelectorAll("rh-price").item(1).setAttribute("value", Math.random() * (99999 - 1) + 1);
}, 1000);
})();
rh-price {
height: 75px;
display: flex;
overflow: hidden;
}
rh-price>div {
transform: translate(0, 0);
transition: transform 400ms ease-in-out;
}
rh-price>div>div {
width: 34px;
text-align: center;
font-size: 50px;
height: 75px;
line-height: 75px;
}
<rh-price value="5000000"></rh-price>
<br>
<rh-price value="600"></rh-price>
我在网上查了一下,只找到了 swift
的版本。在网上,returns 搜索结果的唯一关键字是 ScrollCounter。这种类型的动画是否可能 CSS
HTML
?
如果有人可以向我指出有效的资源或示例,我将在创建有效示例后post支持我的研究。
看看
并混淆 CSS 和 HTML...
更新 1
我找到了以下计数器动画,但仍在尝试弄清楚如何将其实现为货币计数器,包括用于大于 999.99 的数字的可选逗号。
尽管...在现实生活中,我会通过 WebSockets 更新此值。
const genNumber = () => {
document.querySelector("div").style.setProperty("--percent", Math.random());
};
setInterval(genNumber, 3000);
setTimeout(genNumber);
@property --percent {
syntax: "<number>";
initial-value: 0;
inherits: false;
}
@property --temp {
syntax: "<number>";
initial-value: 0;
inherits: false;
}
@property --v1 {
syntax: "<integer>";
initial-value: 0;
inherits: false;
}
@property --v2 {
syntax: "<integer>";
initial-value: 0;
inherits: false;
}
div {
font: 800 40px monospace;
padding: 2rem;
transition: --percent 1s;
--temp: calc(var(--percent) * 100);
--v1: max(var(--temp) - 0.5, 0);
--v2: max((var(--temp) - var(--v1)) * 100 - 0.5, 0);
counter-reset: v1 var(--v1) v2 var(--v2);
}
div::before {
content: counter(v1) "." counter(v2, decimal-leading-zero) "%";
}
<div></div>
我修改了第一个答案,使其在语义上更合理。一路上添加了评论和解释,因为我发现@Phillip Rollins 的方法非常聪明。
// Usage
// Reference to div element that is going to be used as the spinner
const spinnerContainer = document.getElementById('BTCUSD');
spinnerContainer.setAttribute('class', 'spinner-container');
// INITITAL CONSTRUCT
// Array that contains div with class spinner-col HTML elements
const spinnerColumns = [];
// The View will contain the following possible characters
const spinnerCharacters = ['$', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', ','];
// Assumed total length of 12 digits...
for (let i = 0; i < 12; i++) {
// Create Anonymous div
spinnerColumns[i] = document.createElement('div');
// Set Anonymous div class to spinner-col
spinnerColumns[i].setAttribute('class', 'spinner-col');
// For each character in array spinnerCharacters...
for (let spinnerCharacter of spinnerCharacters) {
// Create Anonymous div
const div = document.createElement('div');
// ..containing this character
div.innerText = spinnerCharacter;
// Set Anonymous div class to spinner-char
div.setAttribute('class', 'spinner-char');
// Append Anonymous div spinner-char to Anonymous div spinner-col
spinnerColumns[i].append(div);
}
// Append Anonymous div spinner-col to spinner-container
spinnerContainer.append(spinnerColumns[i]);
}
// RENDER LOGIC
// Set spinner value to number passed in
const setSpinnerValue = (spinnerValue) => {
// The amount of column.style.display = 'none' attributes to initialize
// is equivalent to the amount of digits in the number passed in
for (let i = spinnerValue.length; i < spinnerColumns.length; i++) {
// initially NOT visible
spinnerColumns[i].style.display = 'none';
}
// The amount of column.style.display = 'block' attributes to update
// is equivalent to the amount of digits in the number passed in
for (let i = 0; i < spinnerValue.length; i++) {
const index = spinnerCharacters.indexOf(spinnerValue[i]);
// NOW visible
spinnerColumns[i].style.display = 'block';
// Apply CSS transform style
spinnerColumns[i].style.transform = `translate(0, -${index * 75}px)`;
}
};
// A currency formatter for setting the spinner value
const formatCurrency = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
});
// PRICE FEED
// Just a timer setting random prices every 2 seconds
// Easily replaceble with polling or websockets
setInterval(() => {
const spinnerValue = Math.random() * (999999 - 100000) + 100000;
// Update Price
setSpinnerValue(formatCurrency.format(spinnerValue / 100));
}, 2000);
.spinner-container {
height: 75px;
display: flex;
overflow: hidden;
}
.spinner-col {
box-sizing: border-box;
transform: translate(0, 0);
transition: transform 800ms ease-in-out;
}
.spinner-char {
width: 34px;
text-align: center;
font-size: 50px;
height: 75px;
line-height: 75px;
}
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous">
<div id="BTCUSD"></div>
<h4>BTCUSD</h4>
这是我设法想出的,希望比您自己的答案更符合您的要求。只需创建所有可能的字符,然后使用 CSS 将正确的字符滚动到视图中。
(() => {
// BUILD VIEW
const chars = ["$", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", ','];
const formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
});
const container = document.createElement("div");
container.setAttribute("class", "spinner-container");
const cols = [];
for (let x = 0; x < 12; x++) {
cols[x] = document.createElement("div");
cols[x].setAttribute("class", "spinner-col");
for (let char of chars) {
const div = document.createElement("div");
div.innerText = char;
div.setAttribute("class", "spinner-char");
cols[x].append(div);
}
container.append(cols[x]);
}
document.body.append(container);
// LOGIC
const setValue = (value) => {
for (let x = value.length; x < cols.length; x++) {
cols[x].style.display = "none";
}
for (let x = 0; x < value.length; x++) {
const index = chars.indexOf(value[x]);
cols[x].style.display = "block";
cols[x].style.transform = `translate(0, -${index * 75}px)`;
}
};
setInterval(() => {
const value = Math.random() * (999999 - 100000) + 100000;
setValue(formatter.format(value / 100));
}, 2000);
})();
.spinner-container {
height: 75px;
display: flex;
overflow: hidden;
}
.spinner-col {
box-sizing: border-box;
transform: translate(0, 0);
transition: transform 400ms ease-in-out;
}
.spinner-char {
width: 34px;
text-align: center;
font-size: 50px;
height: 75px;
line-height: 75px;
}
抱歉双重回答,这是对我的另一个回答的扩展,不想增加原始回答的复杂性。使用自定义元素,我们可以使其可重复使用。
const chars = ["$", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", ','];
class RHPriceElement extends HTMLElement {
static get observedAttributes() {
return ['value'];
}
constructor() {
super();
this.formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
});
this._build();
}
attributeChangedCallback(name, _oldValue, newValue) {
if (name === "value") {
const value = this.formatter.format(newValue);
while (this.cols.length < value.length) this._addCol();
for (let x = value.length; x < this.cols.length; x++) {
this.cols[x].style.display = "none";
}
for (let x = 0; x < value.length; x++) {
const index = chars.indexOf(value[x]);
this.cols[x].style.display = "block";
this.cols[x].style.transform = `translate(0, -${index * 75}px)`;
}
}
}
_build() {
this.cols = [];
for (let x = 0; x < 12; x++) {
this._addCol();
}
}
_addCol() {
const x = this.cols.length;
this.cols[x] = document.createElement("div");
this.cols[x].setAttribute("class", "spinner-col");
for (let char of chars) {
const div = document.createElement("div");
div.innerText = char;
div.setAttribute("class", "spinner-char");
this.cols[x].append(div);
}
this.append(this.cols[x]);
}
}
customElements.define('rh-price', RHPriceElement);
(() => {
setInterval(() => {
document.querySelectorAll("rh-price").item(0).setAttribute("value", Math.random() * (9999999 - 10000) + 10000);
document.querySelectorAll("rh-price").item(1).setAttribute("value", Math.random() * (99999 - 1) + 1);
}, 1000);
})();
rh-price {
height: 75px;
display: flex;
overflow: hidden;
}
rh-price>div {
transform: translate(0, 0);
transition: transform 400ms ease-in-out;
}
rh-price>div>div {
width: 34px;
text-align: center;
font-size: 50px;
height: 75px;
line-height: 75px;
}
<rh-price value="5000000"></rh-price>
<br>
<rh-price value="600"></rh-price>