您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Draw Me a Kanji
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/11842/68906/dmak.js
/* * Draw Me A Kanji - v0.3.1 * A funny drawer for your Japanese writings * http://drawmeakanji.com * * Made by Matthieu Bilbille * Under MIT License */ ;(function () { "use strict"; // Create a safe reference to the DrawMeAKanji object for use below. var Dmak = function (text, options) { this.text = text; this.options = extend(Dmak.options, options); this.strokes = []; this.papers = []; this.pointer = 0; this.timeouts = { play : [], erasing : [], drawing : [] }; if (!this.options.skipLoad) { var loader = new DmakLoader(this.options.uri), self = this; loader.load(text, function (data) { self.prepare(data); // Execute custom callback "loaded" here self.options.loaded(self.kanjis); if (self.options.autoplay) { self.render(); } }); } }; // Current version. Dmak.VERSION = "0.2.0"; Dmak.options = { uri: "", skipLoad: false, autoplay: true, height: 109, width: 109, viewBox: { x: 0, y: 0, w: 109, h: 109 }, step: 0.03, element: "draw", stroke: { animated : { drawing : true, erasing : true }, order: { visible: false, attr: { "font-size": "8", "fill": "#999999" } }, attr: { "active": "#BF0000", // may use the keyword "random" here for random color "stroke": "#2C2C2C", "stroke-width": 4, "stroke-linecap": "round", "stroke-linejoin": "round" } }, grid: { show: true, attr: { "stroke": "#CCCCCC", "stroke-width": 0.5, "stroke-dasharray": "--" } }, loaded: function () { }, erased: function () { }, drew: function () { } }; Dmak.fn = Dmak.prototype = { /** * Prepare kanjis and papers for rendering. */ prepare: function (data) { this.kanjis = preprocessStrokes(data); this.papers = giveBirthToRaphael(data.length); if (this.options.grid.show) { showGrid(this.papers); } }, /** * Clean all strokes on papers. */ erase: function (end) { // Cannot have two rendering process for the same draw. Keep it cool. if (this.timeouts.play.length) { return false; } // Don't go behind the beginning. if (this.pointer <= 0) { return false; } if (typeof end === "undefined") { end = 0; } do { this.pointer--; eraseStroke(this.kanjis[this.pointer], this.timeouts.erasing); // Execute custom callback "erased" here this.options.erased(this.pointer); } while (this.pointer > end); }, /** * All the magic happens here. */ render: function (end) { // Cannot have two rendering process for // the same draw. Keep it cool. if (this.timeouts.play.length) { return false; } if (typeof end === "undefined") { end = this.kanjis.length; } else if (end > this.kanjis.length) { return false; } var cb = function (that) { drawStroke(that.papers[that.kanjis[that.pointer].char], that.kanjis[that.pointer], that.timeouts.drawing); // Execute custom callback "drew" here that.options.drew(that.pointer); that.pointer++; that.timeouts.play.shift(); }, delay = 0, i; // Before drawing clear any remaining erasing timeouts for (i = 0; i < this.timeouts.erasing.length; i++) { window.clearTimeout(this.timeouts.erasing[i]); this.timeouts.erasing = []; } for (i = this.pointer; i < end; i++) { if (!Dmak.options.stroke.animated.drawing || delay <= 0) { cb(this); } else { this.timeouts.play.push(setTimeout(cb, delay, this)); } delay += this.kanjis[i].duration; } }, /** * Pause rendering */ pause: function () { for (var i = 0; i < this.timeouts.play.length; i++) { window.clearTimeout(this.timeouts.play[i]); } this.timeouts.play = []; }, /** * Wrap the erase function to remove the x last strokes. */ eraseLastStrokes: function (nbStrokes) { this.erase(this.pointer - nbStrokes); }, /** * Wrap the render function to render the x next strokes. */ renderNextStrokes: function (nbStrokes) { this.render(this.pointer + nbStrokes); } }; // HELPERS /** * Flattens the array of strokes ; 3D > 2D and does some preprocessing while * looping through all the strokes: * - Maps to a character index * - Calculates path length */ function preprocessStrokes(data) { var strokes = [], stroke, length, i, j; for (i = 0; i < data.length; i++) { for (j = 0; j < data[i].length; j++) { length = Raphael.getTotalLength(data[i][j].path); stroke = { "char": i, "length": length, "duration": length * Dmak.options.step * 1000, "path": data[i][j].path, "groups" : data[i][j].groups, "text": data[i][j].text, "object": { "path" : null, "text": null } }; strokes.push(stroke); } } return strokes; } /** * Init Raphael paper objects */ function giveBirthToRaphael(nbChar) { var papers = [], paper, i; for (i = 0; i < nbChar; i++) { paper = new Raphael(Dmak.options.element, Dmak.options.width + "px", Dmak.options.height + "px"); paper.setViewBox(Dmak.options.viewBox.x, Dmak.options.viewBox.y, Dmak.options.viewBox.w, Dmak.options.viewBox.h); paper.canvas.setAttribute("class", "dmak-svg"); papers.push(paper); } return papers.reverse(); } /** * Draw the background grid */ function showGrid(papers) { var i; for (i = 0; i < papers.length; i++) { papers[i].path("M" + (Dmak.options.viewBox.w / 2) + ",0 L" + (Dmak.options.viewBox.w / 2) + "," + Dmak.options.viewBox.h).attr(Dmak.options.grid.attr); papers[i].path("M0," + (Dmak.options.viewBox.h / 2) + " L" + Dmak.options.viewBox.w + "," + (Dmak.options.viewBox.h / 2)).attr(Dmak.options.grid.attr); } } /** * Remove a single stroke ; deletion can be animated if set as so. */ function eraseStroke(stroke, timeouts) { // In some cases the text object may be null: // - Stroke order display disabled // - Stroke already deleted if (stroke.object.text !== null) { stroke.object.text.remove(); } var cb = function() { stroke.object.path.remove(); // Finally properly prepare the object variable stroke.object = { "path" : null, "text" : null }; timeouts.shift(); }; if (Dmak.options.stroke.animated.erasing) { stroke.object.path.node.style.stroke = Dmak.options.stroke.attr.active; timeouts.push(animateStroke(stroke, -1, cb)); } else { cb(); } } /** * Draw a single stroke ; drawing can be animated if set as so. */ function drawStroke(paper, stroke, timeouts) { var cb = function() { // The stroke object may have been already erased when we reach this timeout if (stroke.object.path === null) { return; } var color = Dmak.options.stroke.attr.stroke; if(Dmak.options.stroke.attr.stroke === "random") { color = Raphael.getColor(); } // Revert back to the default color. stroke.object.path.node.style.stroke = color; stroke.object.path.node.style.transition = stroke.object.path.node.style.WebkitTransition = "stroke 400ms ease"; timeouts.shift(); }; stroke.object.path = paper.path(stroke.path); stroke.object.path.attr(Dmak.options.stroke.attr); if (Dmak.options.stroke.order.visible) { showStrokeOrder(paper, stroke); } if (Dmak.options.stroke.animated.drawing) { animateStroke(stroke, 1, cb); } else { cb(); } } /** * Draw a single next to */ function showStrokeOrder(paper, stroke) { stroke.object.text = paper.text(stroke.text.x, stroke.text.y, stroke.text.value); stroke.object.text.attr(Dmak.options.stroke.order.attr); } /** * Animate stroke drawing. * Based on the great article wrote by Jake Archibald * http://jakearchibald.com/2013/animated-line-drawing-svg/ */ function animateStroke(stroke, direction, callback) { stroke.object.path.attr({"stroke": Dmak.options.stroke.attr.active}); stroke.object.path.node.style.transition = stroke.object.path.node.style.WebkitTransition = "none"; // Set up the starting positions stroke.object.path.node.style.strokeDasharray = stroke.length + " " + stroke.length; stroke.object.path.node.style.strokeDashoffset = (direction > 0) ? stroke.length : 0; // Trigger a layout so styles are calculated & the browser // picks up the starting position before animating stroke.object.path.node.getBoundingClientRect(); stroke.object.path.node.style.transition = stroke.object.path.node.style.WebkitTransition = "stroke-dashoffset " + stroke.duration + "ms ease"; // Go! stroke.object.path.node.style.strokeDashoffset = (direction > 0) ? "0" : stroke.length; // Execute the callback once the animation is done // and return the timeout id. return setTimeout(callback, stroke.duration); } /** * Simplistic helper function for extending objects */ function extend(defaults, replacement) { var result = defaults, key; if (arguments.length !== 2) { throw new Error("Missing arguments in extend function"); } for (key in replacement) { if (typeof result[key] === "object") { result[key] = extend(result[key], replacement[key]); } else if (result.hasOwnProperty(key)) { result[key] = replacement[key]; } } return result; } window.Dmak = Dmak; }()); ;(function () { "use strict"; // Create a safe reference to the DrawMeAKanji object for use below. var DmakLoader = function (uri) { this.uri = uri; }; /** * Gather SVG data information for a given set of characters. * By default this action is done while instanciating the Word * object, but it can be skipped, see above */ DmakLoader.prototype.load = function (text, callback) { var paths = [], nbChar = text.length, done = 0, i, callbacks = { done: function (index, data) { paths[index] = data; done++; if (done === nbChar) { callback(paths); } }, error: function (msg) { console.log("Error", msg); } }; for (i = 0; i < nbChar; i++) { loadSvg(this.uri, i, text.charCodeAt(i).toString(16), callbacks); } }; /** * Try to load a SVG file matching the given char code. * @thanks to the incredible work made by KanjiVG * @see: http://kanjivg.tagaini.net */ function loadSvg(uri, index, charCode, callbacks) { var xhr = new XMLHttpRequest(), code = ("00000" + charCode).slice(-5); // Skip space character if(code === "00020" || code === "03000") { callbacks.done(index, { paths: [], texts: [] }); return; } xhr.open("GET", uri + code + ".svg", true); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { callbacks.done(index, parseResponse(xhr.response, code)); } else { callbacks.error(xhr.statusText); } } }; xhr.send(); } /** * Simple parser to extract paths and texts data. */ function parseResponse(response, code) { var data = [], dom = new DOMParser().parseFromString(response, "application/xml"), texts = dom.querySelectorAll("text"), groups = [], i; // Private recursive function to parse DOM content function __parse(element) { var children = element.childNodes, i; for(i = 0; i < children.length; i++) { if(children[i].tagName === "g") { groups.push(children[i].getAttribute("id")); __parse(children[i]); groups.splice(groups.indexOf(children[i].getAttribute("id")), 1); } else if(children[i].tagName === "path") { data.push({ "path" : children[i].getAttribute("d"), "groups" : groups.slice(0) }); } } } // Start parsing __parse(dom.getElementById("kvg:" + code)); // And finally add order mark information for (i = 0; i < texts.length; i++) { data[i].text = { "value" : texts[i].textContent, "x" : texts[i].getAttribute("transform").split(" ")[4], "y" : texts[i].getAttribute("transform").split(" ")[5].replace(")", "") }; } return data; } window.DmakLoader = DmakLoader; }());
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址