SDK OpenXML является правильным инструментом для этого задания, но вам нужно быть осторожным, чтобы использовать подход SAX (простой API для XML), а не подход DOM . Из связанной статьи wikipedia для SAX:
Если DOM работает с документом в целом, SAX-парсеры последовательно работают с каждой частью XML-документа
blockquote>значительно уменьшает объем памяти, потребляемой при обработке больших файлов Excel.
Здесь есть хорошая статья - http://polymathprogrammer.com/2012/ 08/06 / how-to-right-use-openxmlwriter-to-write-large-excel-files /
Адаптировано из этой статьи, вот пример, который выводит строки 115k с 30 столбцами :
public static void LargeExport(string filename) { using (SpreadsheetDocument document = SpreadsheetDocument.Create(filename, SpreadsheetDocumentType.Workbook)) { //this list of attributes will be used when writing a start element List
attributes; OpenXmlWriter writer; document.AddWorkbookPart(); WorksheetPart workSheetPart = document.WorkbookPart.AddNewPart (); writer = OpenXmlWriter.Create(workSheetPart); writer.WriteStartElement(new Worksheet()); writer.WriteStartElement(new SheetData()); for (int rowNum = 1; rowNum <= 115000; ++rowNum) { //create a new list of attributes attributes = new List (); // add the row index attribute to the list attributes.Add(new OpenXmlAttribute("r", null, rowNum.ToString())); //write the row start element with the row index attribute writer.WriteStartElement(new Row(), attributes); for (int columnNum = 1; columnNum <= 30; ++columnNum) { //reset the list of attributes attributes = new List (); // add data type attribute - in this case inline string (you might want to look at the shared strings table) attributes.Add(new OpenXmlAttribute("t", null, "str")); //add the cell reference attribute attributes.Add(new OpenXmlAttribute("r", "", string.Format("{0}{1}", GetColumnName(columnNum), rowNum))); //write the cell start element with the type and reference attributes writer.WriteStartElement(new Cell(), attributes); //write the cell value writer.WriteElement(new CellValue(string.Format("This is Row {0}, Cell {1}", rowNum, columnNum))); // write the end cell element writer.WriteEndElement(); } // write the end row element writer.WriteEndElement(); } // write the end SheetData element writer.WriteEndElement(); // write the end Worksheet element writer.WriteEndElement(); writer.Close(); writer = OpenXmlWriter.Create(document.WorkbookPart); writer.WriteStartElement(new Workbook()); writer.WriteStartElement(new Sheets()); writer.WriteElement(new Sheet() { Name = "Large Sheet", SheetId = 1, Id = document.WorkbookPart.GetIdOfPart(workSheetPart) }); // End Sheets writer.WriteEndElement(); // End Workbook writer.WriteEndElement(); writer.Close(); document.Close(); } } //A simple helper to get the column name from the column index. This is not well tested! private static string GetColumnName(int columnIndex) { int dividend = columnIndex; string columnName = String.Empty; int modifier; while (dividend > 0) { modifier = (dividend - 1) % 26; columnName = Convert.ToChar(65 + modifier).ToString() + columnName; dividend = (int)((dividend - modifier) / 26); } return columnName; }
Если я правильно понимаю ваш вопрос, то этого можно достичь с помощью следующего набора ключевых кадров:
@keyframes fadein {
0% {
opacity: 1;
}
37.5% {
/* 3 / 8 */
opacity: 1;
}
50% {
/* (3 + 1) / 8 */
opacity: 0.0;
}
87.5% {
/* (3 + 1 + 3) / 8 */
opacity: 0.0;
}
100% {
opacity: 1;
}
}
Комментарии показывают, как рассчитываются проценты для различных ключевых кадров на основе ваших требований. Другое ключевое изменение, которое нужно сделать, - это удалить поведение alternate
из правила анимации, чтобы обеспечить повторение цикла анимации в соответствии с требованиями:
/* remove alternate */
animation: fadein 8s linear 0s infinite;
Вот урезанная копия вашего кода для выделить анимированный круг:
function animationListener(event) {
var type = event.type;
var label = type;
if (type=="animationiteration") {
if (app.interval!=null) {
clearInterval(app.interval);
}
app.time = 0;
app.startTime = new Date().getTime();
app.interval = setInterval(intervalFunction, 1000);
intervalFunction();
label = "iteration";
}
else if (type=="animationstart") {
label = "start";
}
else if (type=="animationend") {
label = "end";
}
app.stateLabel.innerHTML = label;
}
function intervalFunction() {
var time = new Date().getTime();
app.timeLabel.innerHTML = Math.round((time - app.startTime)/1000);
app.keyframeLabel.innerHTML = window.getComputedStyle(app.ellipse).content;
}
function loadHandler() {
app.ellipse = document.getElementById("Ellipse_49").parentNode;
app.stateLabel = document.getElementById("stateLabel");
app.timeLabel = document.getElementById("timeLabel");
app.keyframeLabel = document.getElementById("keyframeLabel");
app.ellipse.addEventListener("animationiteration", animationListener);
app.ellipse.addEventListener("animationend", animationListener);
app.ellipse.addEventListener("animationstart", animationListener);
}
document.addEventListener("DOMContentLoaded", loadHandler);
var app = {};
* {
font-family: sans-serif;
font-size: 11px;
letter-spacing: .6px;
}
#Ellipse_49 {
opacity: 1;
fill: rgba(180, 180, 180, 1);
stroke: rgb(112, 112, 112);
stroke-width: 1px;
stroke-linejoin: miter;
stroke-linecap: butt;
stroke-miterlimit: 4;
shape-rendering: auto;
}
.Ellipse_49 {
position: absolute;
overflow: visible;
width: 56px;
height: 56px;
left: 72px;
top: 51px;
/* remove alternate */
animation: fadein 8s linear 0s infinite;
}
#container {
top: 130px;
left: 10px;
position: relative;
display: block;
align-items: center;
}
label {
width: 80px;
display: inline-block;
}
@keyframes fadein {
0% {
opacity: 1;
content: "show";
}
37.5% {
/* 3 / 8 */
opacity: 1;
content: "fade out";
}
50% {
/* (3 + 1) / 8 */
opacity: 0.0;
content: "wait";
}
87.5% {
/* (3 + 1 + 3) / 8 */
opacity: 0.0;
content: "fade in";
}
100% {
opacity: 1;
content: "show";
}
}
<svg class="Ellipse_49">
<ellipse id="Ellipse_49" rx="28" ry="28" cx="28" cy="28">
</ellipse>
</svg>
<div id="container">
<label>time: </label>
<span id="timeLabel"></span>
<br>
<label>state: </label>
<span id="stateLabel"></span>
<br>
<label>key frame: </label>
<span id="keyframeLabel"></span>
</div>
Добавление ответа @ DacreDenny здесь, чтобы я мог изменить его и добавить примечания.
function animationListener(event) {
var type = event.type;
var label = type;
if (type=="animationiteration") {
if (app.interval!=null) {
clearInterval(app.interval);
}
app.time = 0;
app.startTime = new Date().getTime();
app.interval = setInterval(intervalFunction, 15);
intervalFunction();
label = "iteration";
}
else if (type=="animationstart") {
label = "start";
}
else if (type=="animationend") {
label = "end";
}
app.stateLabel.innerHTML = label;
}
function intervalFunction() {
var currentTime = new Date().getTime();
var time = (currentTime - app.startTime)/1000;
var duration = parseFloat(window.getComputedStyle(app.ellipse).animationDuration);
var maxValue = 100;
var position = ((time * maxValue)/duration);
app.timeLabel.innerHTML = Math.round(time);
app.keyframeLabel.innerHTML = window.getComputedStyle(app.ellipse).content;
app.timelineRange.value = position;
app.positionLabel.innerHTML = Math.round(position) + "%";
}
function loadHandler() {
app.ellipse = document.getElementById("Ellipse_49").parentNode;
app.stateLabel = document.getElementById("stateLabel");
app.timeLabel = document.getElementById("timeLabel");
app.keyframeLabel = document.getElementById("keyframeLabel");
app.timelineRange = document.getElementById("timelineRange");
app.positionLabel = document.getElementById("positionLabel");
app.ellipse.addEventListener("animationiteration", animationListener);
app.ellipse.addEventListener("animationend", animationListener);
app.ellipse.addEventListener("animationstart", animationListener);
}
document.addEventListener("DOMContentLoaded", loadHandler);
var app = {};
* {
font-family: sans-serif;
font-size: 11px;
letter-spacing: .6px;
}
@keyframes fadein {
0% {
opacity: 1;
content: "show";
}
37.5% {
/* 3 / 8 */
opacity: 1;
content: "fade out";
}
50% {
/* (3 + 1) / 8 */
opacity: 0.0;
content: "wait";
}
87.5% {
/* (3 + 1 + 3) / 8 */
opacity: 0.0;
content: "fade in";
}
100% {
opacity: 1;
content: "show";
}
}
#Ellipse_49 {
opacity: 1;
fill: rgba(180, 180, 180, 1);
stroke: rgb(112, 112, 112);
stroke-width: 1px;
stroke-linejoin: miter;
stroke-linecap: butt;
stroke-miterlimit: 4;
shape-rendering: auto;
}
.Ellipse_49 {
position: absolute;
overflow: visible;
width: 50px;
height: 50px;
left: 20px;
top: 50px;
/* remove alternate */
animation: fadein 4s linear 0s infinite;
}
#container {
top: 130px;
left: 10px;
position: relative;
display: block;
}
label {
width: 80px;
display: inline-block;
}
input[type=range] {
outline: 0px solid red;
display: block;
width: 90%;
margin-left: 0;
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 8.4px;
cursor: pointer;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
background: rgb(255,255,255);
}
<svg class="Ellipse_49">
<ellipse id="Ellipse_49" rx="28" ry="28" cx="28" cy="28">
</ellipse>
</svg>
<div id="container">
<input id="timelineRange" type="range" value="0" min="0" max="100">
<br>
<label>time: </label>
<span id="timeLabel"></span>
<br>
<label>position: </label>
<span id="positionLabel"></span>
<br>
<label>state: </label>
<span id="stateLabel"></span>
<br>
<label>key frame: </label>
<span id="keyframeLabel"></span>
<br>
<br>
</div>